diff --git a/src/CalcManager/CCalcManager.cpp b/src/CalcManager/CCalcManager.cpp new file mode 100644 index 00000000..5080bbc2 --- /dev/null +++ b/src/CalcManager/CCalcManager.cpp @@ -0,0 +1,126 @@ +#include "pch.h" +#include "CCalcManager.h" +#include "CalculatorManager.h" +#include "CalculatorResource.h" +#include + +using namespace CalculationManager; + +class CalcDisplay : public ICalcDisplay { + +private: + CalculatorManager_CreateParams _params; + +public: + CalcDisplay(CalculatorManager_CreateParams params) { + _params = params; + } + + // Inherited via ICalcDisplay + virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) override + { + std::wstring_convert> convert; + auto str = convert.to_bytes(pszText); + + _params.SetPrimaryDisplay(_params.CalculatorState, str.data(), isError); + } + + virtual void SetIsInError(bool isInError) override + { + _params.SetIsInError(_params.CalculatorState, isInError); + } + + virtual void SetExpressionDisplay( + std::shared_ptr>> const& /*tokens*/, + std::shared_ptr>> const& /*commands*/) override + { + } + + virtual void SetParenthesisNumber(unsigned int count) override + { + _params.SetParenthesisNumber(_params.CalculatorState, count); + } + + virtual void OnNoRightParenAdded() override + { + _params.OnNoRightParenAdded(_params.CalculatorState); + } + + virtual void MaxDigitsReached() override + { + _params.MaxDigitsReached(_params.CalculatorState); + } + + virtual void BinaryOperatorReceived() override + { + _params.BinaryOperatorReceived(_params.CalculatorState); + } + + virtual void OnHistoryItemAdded(unsigned int addedItemIndex) override + { + _params.OnHistoryItemAdded(_params.CalculatorState, addedItemIndex); + } + + virtual void SetMemorizedNumbers(const std::vector& memorizedNumbers) override + { + std::wstring_convert> convert; + + const char** numbers = new const char* [memorizedNumbers.size()]; + + for (size_t i = 0; i < memorizedNumbers.size(); i++) + { + auto str = convert.to_bytes(memorizedNumbers[i]); + auto pData = new char[str.size() + 1]; + strncpy_s(pData, str.size(), str.data(), str.size()); + numbers[i] = pData; + } + + _params.SetMemorizedNumbers(_params.CalculatorState, (unsigned int)memorizedNumbers.size(), numbers); + + for (size_t i = 0; i < memorizedNumbers.size(); i++) + { + delete[] numbers[i]; + } + + delete[] numbers; + } + + virtual void MemoryItemChanged(unsigned int indexOfMemory) override + { + _params.MemoryItemChanged(_params.CalculatorState, indexOfMemory); + } +}; + +class ResourceProvider : public CalculationManager::IResourceProvider { +private: + CalculatorManager_CreateParams _params; + +public: + ResourceProvider(CalculatorManager_CreateParams params) + { + _params = params; + } + + virtual std::wstring GetCEngineString(const std::wstring& id) override { + + std::wstring_convert> convert; + auto str = convert.to_bytes(id); + + auto res = _params.GetCEngineString(_params.ResourceState, str.data()); + + return convert.from_bytes(res); + } +}; + +void* CalculatorManager_Create(CalculatorManager_CreateParams* pParams) { + + auto calcDisplay = new CalcDisplay(*pParams); + auto resProvider = new ResourceProvider(*pParams); + + auto cm = new CalculatorManager(calcDisplay, resProvider); + return cm; +} + +void CalculatorManager_SendCommand(void* manager, int command) { + (static_cast(manager))->SendCommand((Command)command); +} diff --git a/src/CalcManager/CCalcManager.h b/src/CalcManager/CCalcManager.h new file mode 100644 index 00000000..02db9d34 --- /dev/null +++ b/src/CalcManager/CCalcManager.h @@ -0,0 +1,58 @@ +#pragma once + +#include "CalculatorHistory.h" +#include "CalculatorManager.h" +#include "headers/CalcEngine.h" +#include "headers/Rational.h" +#include "headers/ICalcDisplay.h" + + +struct TokenPair { + char* Item1; + int Item2; +}; + +struct ExpressionDisplayData { + int TokenCount; + TokenPair* Tokens; + + int CommandCount; + void* Commands; +}; + +typedef void (*SetPrimaryDisplayFunc)(void* state, const char* text, bool isError); +typedef void (*SetIsInErrorFunc)(void* state, bool isInError); +typedef void (*SetExpressionDisplayFunc)(void* state, ExpressionDisplayData* data); +typedef void (*SetParenthesisNumberFunc)(void* state, unsigned int count); +typedef void (*OnNoRightParenAddedFunc)(void* state); +typedef void (*MaxDigitsReachedFunc)(void* state); +typedef void (*BinaryOperatorReceivedFunc)(void* state); +typedef void (*OnHistoryItemAddedFunc)(void* state, unsigned int addedItemIndex); +typedef void (*SetMemorizedNumbersFunc)(void* state, unsigned int count, const char** memorizedNumbers); +typedef void (*MemoryItemChangedFunc)(void* state, unsigned int indexOfMemory); + +typedef const char* (*GetCEngineStringFunc)(void* state, const char* id); + +struct CalculatorManager_CreateParams { + void* CalculatorState; + + SetPrimaryDisplayFunc SetPrimaryDisplay; + SetIsInErrorFunc SetIsInError; + SetExpressionDisplayFunc SetExpressionDisplay; + SetParenthesisNumberFunc SetParenthesisNumber; + OnNoRightParenAddedFunc OnNoRightParenAdded; + MaxDigitsReachedFunc MaxDigitsReached; + BinaryOperatorReceivedFunc BinaryOperatorReceived; + OnHistoryItemAddedFunc OnHistoryItemAdded; + SetMemorizedNumbersFunc SetMemorizedNumbers; + MemoryItemChangedFunc MemoryItemChanged; + + void* ResourceState; + GetCEngineStringFunc GetCEngineString; +}; + +extern "C" { + __declspec(dllexport) void* CalculatorManager_Create(CalculatorManager_CreateParams* params); + __declspec(dllexport) void CalculatorManager_SendCommand(void* manager, int command); +} + diff --git a/src/CalcManager/CEngine/CalcInput.cpp b/src/CalcManager/CEngine/CalcInput.cpp index 600f9002..2b632d3c 100644 --- a/src/CalcManager/CEngine/CalcInput.cpp +++ b/src/CalcManager/CEngine/CalcInput.cpp @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" using namespace std; using namespace CalcEngine; diff --git a/src/CalcManager/CEngine/CalcUtils.cpp b/src/CalcManager/CEngine/CalcUtils.cpp index 57510dcc..c6933107 100644 --- a/src/CalcManager/CEngine/CalcUtils.cpp +++ b/src/CalcManager/CEngine/CalcUtils.cpp @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "Header Files/CalcEngine.h" -#include "Header Files/CalcUtils.h" +#include "headers/CalcEngine.h" +#include "headers/CalcUtils.h" bool IsOpInRange(OpCode op, uint32_t x, uint32_t y) { diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp index 37add769..9ef4aba6 100644 --- a/src/CalcManager/CEngine/History.cpp +++ b/src/CalcManager/CEngine/History.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" #include "Command.h" #include "CalculatorVector.h" #include "ExpressionCommand.h" diff --git a/src/CalcManager/CEngine/Number.cpp b/src/CalcManager/CEngine/Number.cpp index 7b3be21b..1bdbbba8 100644 --- a/src/CalcManager/CEngine/Number.cpp +++ b/src/CalcManager/CEngine/Number.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. #include -#include "Header Files/Number.h" +#include "headers/Number.h" using namespace std; diff --git a/src/CalcManager/CEngine/Rational.cpp b/src/CalcManager/CEngine/Rational.cpp index a0bcd97d..8e6a345e 100644 --- a/src/CalcManager/CEngine/Rational.cpp +++ b/src/CalcManager/CEngine/Rational.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -#include -#include "Header Files/Rational.h" +//#include +#include "headers/Rational.h" using namespace std; diff --git a/src/CalcManager/CEngine/RationalMath.cpp b/src/CalcManager/CEngine/RationalMath.cpp index 4b1a4b8a..cc03524f 100644 --- a/src/CalcManager/CEngine/RationalMath.cpp +++ b/src/CalcManager/CEngine/RationalMath.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "Header Files/RationalMath.h" +#include "headers/RationalMath.h" using namespace std; using namespace CalcEngine; diff --git a/src/CalcManager/CEngine/calc.cpp b/src/CalcManager/CEngine/calc.cpp index c71d2927..5bfb08d8 100644 --- a/src/CalcManager/CEngine/calc.cpp +++ b/src/CalcManager/CEngine/calc.cpp @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" #include "CalculatorResource.h" using namespace std; diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp index eabb7f94..a5ef70de 100644 --- a/src/CalcManager/CEngine/scicomm.cpp +++ b/src/CalcManager/CEngine/scicomm.cpp @@ -14,8 +14,8 @@ \****************************************************************************/ #include -#include "Header Files/CalcEngine.h" -#include "Header Files/CalcUtils.h" +#include "headers/CalcEngine.h" +#include "headers/CalcUtils.h" using namespace std; using namespace CalcEngine; diff --git a/src/CalcManager/CEngine/scidisp.cpp b/src/CalcManager/CEngine/scidisp.cpp index 8d4eed1f..3d67756b 100644 --- a/src/CalcManager/CEngine/scidisp.cpp +++ b/src/CalcManager/CEngine/scidisp.cpp @@ -15,7 +15,7 @@ #include #include -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" using namespace std; using namespace CalcEngine; @@ -48,7 +48,6 @@ typedef struct bool bUseSep; } LASTDISP; -LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false }; // Truncates if too big, makes it a non negative - the number in rat. Doesn't do anything if not in INT mode CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational const& rat) @@ -77,6 +76,8 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con void CCalcEngine::DisplayNum(void) { + static LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false }; + // // Only change the display if // we are in record mode -OR- diff --git a/src/CalcManager/CEngine/scifunc.cpp b/src/CalcManager/CEngine/scifunc.cpp index 5684ce43..91a16915 100644 --- a/src/CalcManager/CEngine/scifunc.cpp +++ b/src/CalcManager/CEngine/scifunc.cpp @@ -16,7 +16,7 @@ /*** ***/ /*** ***/ /**************************************************************************/ -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" using namespace std; using namespace CalcEngine; diff --git a/src/CalcManager/CEngine/scioper.cpp b/src/CalcManager/CEngine/scioper.cpp index e41aee21..43c2685b 100644 --- a/src/CalcManager/CEngine/scioper.cpp +++ b/src/CalcManager/CEngine/scioper.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" using namespace CalcEngine; using namespace CalcEngine::RationalMath; diff --git a/src/CalcManager/CEngine/sciset.cpp b/src/CalcManager/CEngine/sciset.cpp index 676ab0eb..935f3e49 100644 --- a/src/CalcManager/CEngine/sciset.cpp +++ b/src/CalcManager/CEngine/sciset.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" using namespace CalcEngine; using namespace CalcEngine::RationalMath; diff --git a/src/CalcManager/CalcManager.vcxproj b/src/CalcManager/CalcManager.vcxproj index 4d03a5c9..f5fdf46c 100644 --- a/src/CalcManager/CalcManager.vcxproj +++ b/src/CalcManager/CalcManager.vcxproj @@ -41,7 +41,7 @@ CalcManager false en-US - 15.0 + 16.0 true Windows Store 10.0 @@ -56,46 +56,46 @@ StaticLibrary true - v141 + v142 StaticLibrary true - v141 + v142 StaticLibrary true - v141 + v142 - StaticLibrary + DynamicLibrary true - v141 + v142 StaticLibrary false true - v141 + v142 StaticLibrary false true - v141 + v142 StaticLibrary false true - v141 + v142 StaticLibrary false true - v141 + v142 @@ -158,6 +158,7 @@ Level4 true pch.h + _UNICODE;UNICODE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions) Console @@ -222,7 +223,7 @@ false true /Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions) - _UNICODE;UNICODE;%(PreprocessorDefinitions) + _UNICODE;UNICODE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions) $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true @@ -290,21 +291,23 @@ + + - - - - - - - - - - - - + + + + + + + + + + + + @@ -314,6 +317,7 @@ + diff --git a/src/CalcManager/CalcManager.vcxproj.filters b/src/CalcManager/CalcManager.vcxproj.filters index 2ca11666..40d45f51 100644 --- a/src/CalcManager/CalcManager.vcxproj.filters +++ b/src/CalcManager/CalcManager.vcxproj.filters @@ -7,7 +7,7 @@ {a1bae6f0-0a01-447d-9a3a-5c65bcd384e6} - + {5149465e-c5c9-48a2-b676-f11380b733a0} @@ -89,27 +89,13 @@ CEngine + - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - RatPack @@ -120,45 +106,49 @@ RatPack - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files + + headers - - Header Files + + headers - - Header Files + + headers - - Header Files + + headers - - Header Files + + headers - - Header Files + + headers - - Header Files + + headers + + headers + + + headers + + + headers + + + headers + + + headers + + + headers + + - + \ No newline at end of file diff --git a/src/CalcManager/CalculatorHistory.h b/src/CalcManager/CalculatorHistory.h index 75b74255..f4bde896 100644 --- a/src/CalcManager/CalculatorHistory.h +++ b/src/CalcManager/CalculatorHistory.h @@ -3,7 +3,7 @@ #pragma once #include "ExpressionCommandInterface.h" -#include "Header Files/IHistoryDisplay.h" +#include "headers/IHistoryDisplay.h" namespace CalculationManager { diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index 569e0114..2b224020 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include // for UCHAR_MAX -#include "Header Files/CalcEngine.h" +#include "headers/CalcEngine.h" #include "CalculatorManager.h" #include "CalculatorResource.h" diff --git a/src/CalcManager/CalculatorManager.h b/src/CalcManager/CalculatorManager.h index a288bdf2..4fc47d4b 100644 --- a/src/CalcManager/CalculatorManager.h +++ b/src/CalcManager/CalculatorManager.h @@ -4,9 +4,9 @@ #pragma once #include "CalculatorHistory.h" -#include "Header Files/CalcEngine.h" -#include "Header Files/Rational.h" -#include "Header Files/ICalcDisplay.h" +#include "headers/CalcEngine.h" +#include "headers/Rational.h" +#include "headers/ICalcDisplay.h" namespace CalculationManager { @@ -153,4 +153,4 @@ namespace CalculationManager void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector> const& history); void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode); }; -} +} \ No newline at end of file diff --git a/src/CalcManager/CalculatorVector.h b/src/CalcManager/CalculatorVector.h index e89b55e4..3795ecf0 100644 --- a/src/CalcManager/CalculatorVector.h +++ b/src/CalcManager/CalculatorVector.h @@ -5,10 +5,17 @@ #include #include -#include +#include +#include #include "Ratpack/CalcErr.h" #include // for std::out_of_range + +#if !defined(__WEBASSEMBLY__) +#include #include // for SAL +#endif + +#include "compat.h" template class CalculatorVector diff --git a/src/CalcManager/ExpressionCommand.cpp b/src/CalcManager/ExpressionCommand.cpp index 079e02aa..9ea0ad57 100644 --- a/src/CalcManager/ExpressionCommand.cpp +++ b/src/CalcManager/ExpressionCommand.cpp @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include -#include "Header Files/CCommand.h" +#include "headers/CCommand.h" #include "CalculatorVector.h" #include "ExpressionCommand.h" diff --git a/src/CalcManager/ExpressionCommand.h b/src/CalcManager/ExpressionCommand.h index 91d41e60..22d8a40b 100644 --- a/src/CalcManager/ExpressionCommand.h +++ b/src/CalcManager/ExpressionCommand.h @@ -3,8 +3,8 @@ #pragma once #include "ExpressionCommandInterface.h" -#include "Header Files/CalcEngine.h" -#include "Header Files/Rational.h" +#include "headers/CalcEngine.h" +#include "headers/Rational.h" class CParentheses final : public IParenthesisCommand { diff --git a/src/CalcManager/Ratpack/conv.cpp b/src/CalcManager/Ratpack/conv.cpp index 9a944ea5..a9adcb74 100644 --- a/src/CalcManager/Ratpack/conv.cpp +++ b/src/CalcManager/Ratpack/conv.cpp @@ -18,10 +18,11 @@ //--------------------------------------------------------------------------- #include -#include +// #include #include #include // for memmove, memcpy #include "ratpak.h" +#include "compat.h" using namespace std; @@ -48,7 +49,7 @@ wchar_t g_decimalSeparator = L'.'; #define Calc_UInt32x32To64(a, b) ((uint64_t)((uint32_t)(a)) * (uint64_t)((uint32_t)(b))) #endif -#elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) +#elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__EMSCRIPTEN__) #ifndef Calc_UInt32x32To64 #define Calc_UInt32x32To64(a, b) (uint64_t)((uint64_t)(uint32_t)(a) * (uint32_t)(b)) diff --git a/src/CalcManager/Ratpack/ratconst.h b/src/CalcManager/Ratpack/ratconst.h index 23efaabb..00f10ad7 100644 --- a/src/CalcManager/Ratpack/ratconst.h +++ b/src/CalcManager/Ratpack/ratconst.h @@ -1,594 +1,594 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_num_one = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_num_two = { 1, - 1, - 0, - { - 2, - } }; + 1, + 0, + { + 2, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_num_five = { 1, - 1, - 0, - { - 5, - } }; + 1, + 0, + { + 5, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_num_six = { 1, - 1, - 0, - { - 6, - } }; + 1, + 0, + { + 6, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_num_ten = { 1, - 1, - 0, - { - 10, - } }; + 1, + 0, + { + 10, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_smallest = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; inline const NUMBER init_q_rat_smallest = { 1, - 4, - 0, - { - 0, - 190439170, - 901055854, - 10097, - } }; + 4, + 0, + { + 0, + 190439170, + 901055854, + 10097, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_negsmallest = { -1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; inline const NUMBER init_q_rat_negsmallest = { 1, - 4, - 0, - { - 0, - 190439170, - 901055854, - 10097, - } }; + 4, + 0, + { + 0, + 190439170, + 901055854, + 10097, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_pt_eight_five = { 1, - 1, - 0, - { - 85, - } }; + 1, + 0, + { + 85, + } }; inline const NUMBER init_q_pt_eight_five = { 1, - 1, - 0, - { - 100, - } }; + 1, + 0, + { + 100, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_six = { 1, - 1, - 0, - { - 6, - } }; + 1, + 0, + { + 6, + } }; inline const NUMBER init_q_rat_six = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_two = { 1, - 1, - 0, - { - 2, - } }; + 1, + 0, + { + 2, + } }; inline const NUMBER init_q_rat_two = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_zero = { 1, - 1, - 0, - { - 0, - } }; + 1, + 0, + { + 0, + } }; inline const NUMBER init_q_rat_zero = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_one = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; inline const NUMBER init_q_rat_one = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_neg_one = { -1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; inline const NUMBER init_q_rat_neg_one = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_half = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; inline const NUMBER init_q_rat_half = { 1, - 1, - 0, - { - 2, - } }; + 1, + 0, + { + 2, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_ten = { 1, - 1, - 0, - { - 10, - } }; + 1, + 0, + { + 10, + } }; inline const NUMBER init_q_rat_ten = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_pi = { 1, - 6, - 0, - { - 125527896, - 283898350, - 1960493936, - 1672850762, - 1288168272, - 8, - } }; + 6, + 0, + { + 125527896, + 283898350, + 1960493936, + 1672850762, + 1288168272, + 8, + } }; inline const NUMBER init_q_pi = { 1, - 6, - 0, - { - 1288380402, - 1120116153, - 1860424692, - 1944118326, - 1583591604, - 2, - } }; + 6, + 0, + { + 1288380402, + 1120116153, + 1860424692, + 1944118326, + 1583591604, + 2, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_two_pi = { 1, - 6, - 0, - { - 251055792, - 567796700, - 1773504224, - 1198217877, - 428852897, - 17, - } }; + 6, + 0, + { + 251055792, + 567796700, + 1773504224, + 1198217877, + 428852897, + 17, + } }; inline const NUMBER init_q_two_pi = { 1, - 6, - 0, - { - 1288380402, - 1120116153, - 1860424692, - 1944118326, - 1583591604, - 2, - } }; + 6, + 0, + { + 1288380402, + 1120116153, + 1860424692, + 1944118326, + 1583591604, + 2, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_pi_over_two = { 1, - 6, - 0, - { - 125527896, - 283898350, - 1960493936, - 1672850762, - 1288168272, - 8, - } }; + 6, + 0, + { + 125527896, + 283898350, + 1960493936, + 1672850762, + 1288168272, + 8, + } }; inline const NUMBER init_q_pi_over_two = { 1, - 6, - 0, - { - 429277156, - 92748659, - 1573365737, - 1740753005, - 1019699561, - 5, - } }; + 6, + 0, + { + 429277156, + 92748659, + 1573365737, + 1740753005, + 1019699561, + 5, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_one_pt_five_pi = { 1, - 6, - 0, - { - 1241201312, - 270061909, - 1051574664, - 1924965045, - 1340320627, - 70, - } }; + 6, + 0, + { + 1241201312, + 270061909, + 1051574664, + 1924965045, + 1340320627, + 70, + } }; inline const NUMBER init_q_one_pt_five_pi = { 1, - 6, - 0, - { - 1579671539, - 1837970263, - 1067644340, - 523549916, - 2119366659, - 14, - } }; + 6, + 0, + { + 1579671539, + 1837970263, + 1067644340, + 523549916, + 2119366659, + 14, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_e_to_one_half = { 1, - 6, - 0, - { - 256945612, - 216219427, - 223516738, - 477442596, - 581063757, - 23, - } }; + 6, + 0, + { + 256945612, + 216219427, + 223516738, + 477442596, + 581063757, + 23, + } }; inline const NUMBER init_q_e_to_one_half = { 1, - 6, - 0, - { - 1536828363, - 698484484, - 1127331835, - 224219346, - 245499408, - 14, - } }; + 6, + 0, + { + 1536828363, + 698484484, + 1127331835, + 224219346, + 245499408, + 14, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_exp = { 1, - 6, - 0, - { - 943665199, - 1606559160, - 1094967530, - 1759391384, - 1671799163, - 1123581, - } }; + 6, + 0, + { + 943665199, + 1606559160, + 1094967530, + 1759391384, + 1671799163, + 1123581, + } }; inline const NUMBER init_q_rat_exp = { 1, - 6, - 0, - { - 879242208, - 2022880100, - 617392930, - 1374929092, - 1367479163, - 413342, - } }; + 6, + 0, + { + 879242208, + 2022880100, + 617392930, + 1374929092, + 1367479163, + 413342, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_ln_ten = { 1, - 6, - 0, - { - 2086268922, - 165794492, - 1416063951, - 1851428830, - 1893239400, - 65366841, - } }; + 6, + 0, + { + 2086268922, + 165794492, + 1416063951, + 1851428830, + 1893239400, + 65366841, + } }; inline const NUMBER init_q_ln_ten = { 1, - 6, - 0, - { - 26790652, - 564532679, - 783998273, - 216030448, - 1564709968, - 28388458, - } }; + 6, + 0, + { + 26790652, + 564532679, + 783998273, + 216030448, + 1564709968, + 28388458, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_ln_two = { 1, - 6, - 0, - { - 1789230241, - 1057927868, - 715399197, - 908801241, - 1411265331, - 3, - } }; + 6, + 0, + { + 1789230241, + 1057927868, + 715399197, + 908801241, + 1411265331, + 3, + } }; inline const NUMBER init_q_ln_two = { 1, - 6, - 0, - { - 1559869847, - 1930657510, - 1228561531, - 219003871, - 593099283, - 5, - } }; + 6, + 0, + { + 1559869847, + 1930657510, + 1228561531, + 219003871, + 593099283, + 5, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rad_to_deg = { 1, - 6, - 0, - { - 2127722024, - 1904928383, - 2016479213, - 2048947859, - 1578647346, - 492, - } }; + 6, + 0, + { + 2127722024, + 1904928383, + 2016479213, + 2048947859, + 1578647346, + 492, + } }; inline const NUMBER init_q_rad_to_deg = { 1, - 6, - 0, - { - 125527896, - 283898350, - 1960493936, - 1672850762, - 1288168272, - 8, - } }; + 6, + 0, + { + 125527896, + 283898350, + 1960493936, + 1672850762, + 1288168272, + 8, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rad_to_grad = { 1, - 6, - 0, - { - 2125526288, - 684931327, - 570267400, - 129125085, - 1038224725, - 547, - } }; + 6, + 0, + { + 2125526288, + 684931327, + 570267400, + 129125085, + 1038224725, + 547, + } }; inline const NUMBER init_q_rad_to_grad = { 1, - 6, - 0, - { - 125527896, - 283898350, - 1960493936, - 1672850762, - 1288168272, - 8, - } }; + 6, + 0, + { + 125527896, + 283898350, + 1960493936, + 1672850762, + 1288168272, + 8, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_qword = { 1, - 3, - 0, - { - 2147483647, - 2147483647, - 3, - } }; + 3, + 0, + { + 2147483647, + 2147483647, + 3, + } }; inline const NUMBER init_q_rat_qword = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_dword = { 1, - 2, - 0, - { - 2147483647, - 1, - } }; + 2, + 0, + { + 2147483647, + 1, + } }; inline const NUMBER init_q_rat_dword = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_max_i32 = { 1, - 1, - 0, - { - 2147483647, - } }; + 1, + 0, + { + 2147483647, + } }; inline const NUMBER init_q_rat_max_i32 = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_min_i32 = { -1, - 2, - 0, - { - 0, - 1, - } }; + 2, + 0, + { + 0, + 1, + } }; inline const NUMBER init_q_rat_min_i32 = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_word = { 1, - 1, - 0, - { - 65535, - } }; + 1, + 0, + { + 65535, + } }; inline const NUMBER init_q_rat_word = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_byte = { 1, - 1, - 0, - { - 255, - } }; + 1, + 0, + { + 255, + } }; inline const NUMBER init_q_rat_byte = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_400 = { 1, - 1, - 0, - { - 400, - } }; + 1, + 0, + { + 400, + } }; inline const NUMBER init_q_rat_400 = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_360 = { 1, - 1, - 0, - { - 360, - } }; + 1, + 0, + { + 360, + } }; inline const NUMBER init_q_rat_360 = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_200 = { 1, - 1, - 0, - { - 200, - } }; + 1, + 0, + { + 200, + } }; inline const NUMBER init_q_rat_200 = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_180 = { 1, - 1, - 0, - { - 180, - } }; + 1, + 0, + { + 180, + } }; inline const NUMBER init_q_rat_180 = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_max_exp = { 1, - 1, - 0, - { - 100000, - } }; + 1, + 0, + { + 100000, + } }; inline const NUMBER init_q_rat_max_exp = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_min_exp = { -1, - 1, - 0, - { - 100000, - } }; + 1, + 0, + { + 100000, + } }; inline const NUMBER init_q_rat_min_exp = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_max_fact = { 1, - 1, - 0, - { - 3249, - } }; + 1, + 0, + { + 3249, + } }; inline const NUMBER init_q_rat_max_fact = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; // Autogenerated by _dumprawrat in support.cpp inline const NUMBER init_p_rat_min_fact = { -1, - 1, - 0, - { - 1000, - } }; + 1, + 0, + { + 1000, + } }; inline const NUMBER init_q_rat_min_fact = { 1, - 1, - 0, - { - 1, - } }; + 1, + 0, + { + 1, + } }; diff --git a/src/CalcManager/Ratpack/ratpak.h b/src/CalcManager/Ratpack/ratpak.h index 2e7c973c..c18a70fd 100644 --- a/src/CalcManager/Ratpack/ratpak.h +++ b/src/CalcManager/Ratpack/ratpak.h @@ -21,7 +21,8 @@ #include #include "CalcErr.h" #include // for memmove -#include // for SAL +// #include // for SAL +#include "compat.h" static constexpr uint32_t BASEXPWR = 31L; // Internal log2(BASEX) static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculations, hope to raise diff --git a/src/CalcManager/compat.h b/src/CalcManager/compat.h new file mode 100644 index 00000000..b7c9ba5f --- /dev/null +++ b/src/CalcManager/compat.h @@ -0,0 +1,30 @@ +#pragma once + +#if defined(__WEBASSEMBLY__) + +#define HRESULT long +#define _In_opt_ +#define _Out_ +#define _In_ +#define _Inout_ +#define __in_opt + +#define S_OK ((HRESULT)0L) +#define S_FALSE ((HRESULT)1L) +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) +#define E_BOUNDS _HRESULT_TYPEDEF_(0x8000000BL) +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#define FAILED(hr) (((HRESULT)(hr)) < 0) +// +#define LOWORD(_dw) ((WORD)(((DWORD_PTR)(_dw)) & 0xffff)) +#define HIWORD(_dw) ((WORD)((((DWORD_PTR)(_dw)) >> 16) & 0xffff)) +#define LODWORD(_qw) ((DWORD)(_qw)) +#define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff)) + +typedef unsigned long DWORD; + +#define HRESULT_CODE(hr) ((hr)&0xFFFF) +#define SCODE_CODE(sc) ((sc)&0xFFFF) + +#endif \ No newline at end of file diff --git a/src/CalcManager/Header Files/CCommand.h b/src/CalcManager/headers/CCommand.h similarity index 100% rename from src/CalcManager/Header Files/CCommand.h rename to src/CalcManager/headers/CCommand.h diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/headers/CalcEngine.h similarity index 100% rename from src/CalcManager/Header Files/CalcEngine.h rename to src/CalcManager/headers/CalcEngine.h diff --git a/src/CalcManager/Header Files/CalcInput.h b/src/CalcManager/headers/CalcInput.h similarity index 100% rename from src/CalcManager/Header Files/CalcInput.h rename to src/CalcManager/headers/CalcInput.h diff --git a/src/CalcManager/Header Files/CalcUtils.h b/src/CalcManager/headers/CalcUtils.h similarity index 100% rename from src/CalcManager/Header Files/CalcUtils.h rename to src/CalcManager/headers/CalcUtils.h diff --git a/src/CalcManager/Header Files/EngineStrings.h b/src/CalcManager/headers/EngineStrings.h similarity index 99% rename from src/CalcManager/Header Files/EngineStrings.h rename to src/CalcManager/headers/EngineStrings.h index a85fc508..b59a8703 100644 --- a/src/CalcManager/Header Files/EngineStrings.h +++ b/src/CalcManager/headers/EngineStrings.h @@ -17,6 +17,7 @@ #pragma once #include +#include inline constexpr auto IDS_ERRORS_FIRST = 99; diff --git a/src/CalcManager/Header Files/History.h b/src/CalcManager/headers/History.h similarity index 99% rename from src/CalcManager/Header Files/History.h rename to src/CalcManager/headers/History.h index b6d6d8db..38c14558 100644 --- a/src/CalcManager/Header Files/History.h +++ b/src/CalcManager/headers/History.h @@ -7,6 +7,7 @@ #include "ICalcDisplay.h" #include "IHistoryDisplay.h" #include "Rational.h" +#include "compat.h" // maximum depth you can get by precedence. It is just an array's size limit. static constexpr size_t MAXPRECDEPTH = 25; diff --git a/src/CalcManager/Header Files/ICalcDisplay.h b/src/CalcManager/headers/ICalcDisplay.h similarity index 100% rename from src/CalcManager/Header Files/ICalcDisplay.h rename to src/CalcManager/headers/ICalcDisplay.h diff --git a/src/CalcManager/Header Files/IHistoryDisplay.h b/src/CalcManager/headers/IHistoryDisplay.h similarity index 100% rename from src/CalcManager/Header Files/IHistoryDisplay.h rename to src/CalcManager/headers/IHistoryDisplay.h diff --git a/src/CalcManager/Header Files/Number.h b/src/CalcManager/headers/Number.h similarity index 100% rename from src/CalcManager/Header Files/Number.h rename to src/CalcManager/headers/Number.h diff --git a/src/CalcManager/Header Files/RadixType.h b/src/CalcManager/headers/RadixType.h similarity index 100% rename from src/CalcManager/Header Files/RadixType.h rename to src/CalcManager/headers/RadixType.h diff --git a/src/CalcManager/Header Files/Rational.h b/src/CalcManager/headers/Rational.h similarity index 99% rename from src/CalcManager/Header Files/Rational.h rename to src/CalcManager/headers/Rational.h index 8ded3c27..ad611269 100644 --- a/src/CalcManager/Header Files/Rational.h +++ b/src/CalcManager/headers/Rational.h @@ -4,6 +4,7 @@ #pragma once #include "Number.h" +#include "compat.h" namespace CalcEngine { diff --git a/src/CalcManager/Header Files/RationalMath.h b/src/CalcManager/headers/RationalMath.h similarity index 100% rename from src/CalcManager/Header Files/RationalMath.h rename to src/CalcManager/headers/RationalMath.h diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp deleted file mode 100644 index e5f55ed4..00000000 --- a/src/CalcViewModel/ApplicationViewModel.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "ApplicationViewModel.h" -#include "Common/TraceLogger.h" -#include "Common/AppResourceProvider.h" -#include "StandardCalculatorViewModel.h" -#include "DateCalculatorViewModel.h" -#include "DataLoaders/CurrencyHttpClient.h" -#include "DataLoaders/CurrencyDataLoader.h" -#include "DataLoaders/UnitConverterDataLoader.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::DataLoaders; -using namespace CalculatorApp::ViewModel; -using namespace CalculationManager; -using namespace Platform; -using namespace Platform::Collections; -using namespace std; -using namespace Windows::System; -using namespace Windows::Storage; -using namespace Utils; -using namespace Windows::Foundation::Collections; -using namespace Windows::Globalization; -using namespace Windows::UI::ViewManagement; -using namespace Windows::UI::Core; -using namespace Windows::UI::Xaml::Automation; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Data; -using namespace Windows::UI::Xaml::Input; -using namespace Windows::UI::Xaml::Media; - -namespace -{ - StringReference CategoriesPropertyName(L"Categories"); - StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility"); -} - -ApplicationViewModel::ApplicationViewModel() - : m_CalculatorViewModel(nullptr) - , m_DateCalcViewModel(nullptr) - , m_ConverterViewModel(nullptr) - , m_PreviousMode(ViewMode::None) - , m_mode(ViewMode::None) - , m_categories(nullptr) -{ - SetMenuCategories(); -} - -void ApplicationViewModel::Mode::set(ViewMode value) -{ - if (m_mode != value) - { - PreviousMode = m_mode; - m_mode = value; - OnModeChanged(); - RaisePropertyChanged(ModePropertyName); - } -} - -void ApplicationViewModel::Categories::set(IObservableVector ^ value) -{ - if (m_categories != value) - { - m_categories = value; - RaisePropertyChanged(CategoriesPropertyName); - } -} - -void ApplicationViewModel::Initialize(ViewMode mode) -{ - if (!NavCategory::IsValidViewMode(mode)) - { - mode = ViewMode::Standard; - } - - try - { - Mode = mode; - } - catch (const std::exception& e) - { - TraceLogger::GetInstance().LogStandardException(__FUNCTIONW__, e); - if (!TryRecoverFromNavigationModeFailure()) - { - // Could not navigate to standard mode either. - // Throw the original exception so we have a good stack to debug. - throw; - } - } - catch (Exception ^ e) - { - TraceLogger::GetInstance().LogPlatformException(__FUNCTIONW__, e); - if (!TryRecoverFromNavigationModeFailure()) - { - // Could not navigate to standard mode either. - // Throw the original exception so we have a good stack to debug. - throw; - } - } -} - -bool ApplicationViewModel::TryRecoverFromNavigationModeFailure() -{ - // Here we are simply trying to recover from being unable to navigate to a mode. - // Try falling back to standard mode and if there are *any* exceptions, we should - // fail because something is seriously wrong. - try - { - Mode = ViewMode::Standard; - return true; - } - catch (...) - { - return false; - } -} - -void ApplicationViewModel::OnModeChanged() -{ - assert(NavCategory::IsValidViewMode(m_mode)); - TraceLogger::GetInstance().LogModeChangeBegin(m_PreviousMode, m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); - if (NavCategory::IsCalculatorViewMode(m_mode)) - { - TraceLogger::GetInstance().LogCalculatorModeViewed(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); - if (!m_CalculatorViewModel) - { - m_CalculatorViewModel = ref new StandardCalculatorViewModel(); - } - m_CalculatorViewModel->SetCalculatorType(m_mode); - } - else if (NavCategory::IsDateCalculatorViewMode(m_mode)) - { - TraceLogger::GetInstance().LogDateCalculatorModeViewed(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); - if (!m_DateCalcViewModel) - { - m_DateCalcViewModel = ref new DateCalculatorViewModel(); - } - } - else if (NavCategory::IsConverterViewMode(m_mode)) - { - TraceLogger::GetInstance().LogConverterModeViewed(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); - if (!m_ConverterViewModel) - { - auto dataLoader = make_shared(ref new GeographicRegion()); - auto currencyDataLoader = make_shared(make_unique()); - m_ConverterViewModel = ref new UnitConverterViewModel(make_shared(dataLoader, currencyDataLoader)); - } - - m_ConverterViewModel->Mode = m_mode; - } - - auto resProvider = AppResourceProvider::GetInstance(); - CategoryName = resProvider.GetResourceString(NavCategory::GetNameResourceKey(m_mode)); - - // This is the only place where a ViewMode enum should be cast to an int. - // - // Save the changed mode, so that the new window launches in this mode. - // Don't save until after we have adjusted to the new mode, so we don't save a mode that fails to load. - ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategory::Serialize(m_mode)); - - TraceLogger::GetInstance().LogModeChangeEnd(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); - RaisePropertyChanged(ClearMemoryVisibilityPropertyName); -} - -void ApplicationViewModel::OnCopyCommand(Object ^ parameter) -{ - if (NavCategory::IsConverterViewMode(m_mode)) - { - ConverterViewModel->OnCopyCommand(parameter); - } - else if (NavCategory::IsDateCalculatorViewMode(m_mode)) - { - DateCalcViewModel->OnCopyCommand(parameter); - } - else - { - CalculatorViewModel->OnCopyCommand(parameter); - } -} - -void ApplicationViewModel::OnPasteCommand(Object ^ parameter) -{ - if (NavCategory::IsConverterViewMode(m_mode)) - { - ConverterViewModel->OnPasteCommand(parameter); - } - else if (NavCategory::IsCalculatorViewMode(m_mode)) - { - CalculatorViewModel->OnPasteCommand(parameter); - } -} - -void ApplicationViewModel::SetMenuCategories() -{ - // Use the Categories property instead of the backing variable - // because we want to take advantage of binding updates and - // property setter logic. - Categories = NavCategoryGroup::CreateMenuOptions(); -} diff --git a/src/CalcViewModel/ApplicationViewModel.h b/src/CalcViewModel/ApplicationViewModel.h deleted file mode 100644 index dffa3b9b..00000000 --- a/src/CalcViewModel/ApplicationViewModel.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "StandardCalculatorViewModel.h" -#include "DateCalculatorViewModel.h" -#include "UnitConverterViewModel.h" - -namespace CalculatorApp -{ - namespace ViewModel - { - [Windows::UI::Xaml::Data::Bindable] public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - public: - ApplicationViewModel(); - - void Initialize(CalculatorApp::Common::ViewMode mode); // Use for first init, use deserialize for rehydration - - OBSERVABLE_OBJECT(); - OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel); - OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel ^, DateCalcViewModel); - OBSERVABLE_PROPERTY_RW(UnitConverterViewModel ^, ConverterViewModel); - OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode); - OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, CategoryName); - - COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand); - COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand); - - property CalculatorApp::Common::ViewMode Mode - { - CalculatorApp::Common::ViewMode get() - { - return m_mode; - } - - void set(CalculatorApp::Common::ViewMode value); - } - static property Platform::String^ ModePropertyName - { - Platform::String^ get() - { - return Platform::StringReference(L"Mode"); - } - } - - property Windows::Foundation::Collections::IObservableVector^ Categories - { - Windows::Foundation::Collections::IObservableVector^ get() - { - return m_categories; - } - - void set(Windows::Foundation::Collections::IObservableVector^ value); - } - - property Windows::UI::Xaml::Visibility ClearMemoryVisibility - { - Windows::UI::Xaml::Visibility get() - { - return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode) ? Windows::UI::Xaml::Visibility::Visible - : Windows::UI::Xaml::Visibility::Collapsed; - } - } - - private: - bool TryRecoverFromNavigationModeFailure(); - - void OnModeChanged(); - - void OnCopyCommand(Platform::Object ^ parameter); - void OnPasteCommand(Platform::Object ^ parameter); - - void SetMenuCategories(); - - CalculatorApp::Common::ViewMode m_mode; - Windows::Foundation::Collections::IObservableVector ^ m_categories; - }; - } -} diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj deleted file mode 100644 index e2e98ab9..00000000 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ /dev/null @@ -1,425 +0,0 @@ - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - {90e9761d-9262-4773-942d-caeae75d7140} - StaticLibrary - CalcViewModel - en-US - 14.0 - true - Windows Store - 10.0.17763.0 - 10.0.17134.0 - 10.0 - - - - StaticLibrary - true - v141 - - - StaticLibrary - true - v141 - - - StaticLibrary - true - v141 - - - StaticLibrary - true - v141 - - - StaticLibrary - false - true - v141 - - - StaticLibrary - false - true - v141 - - - StaticLibrary - false - true - v141 - - - StaticLibrary - false - true - v141 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - Use - true - true - $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) - 4453 - /bigobj /await /std:c++17 %(AdditionalOptions) - Level4 - true - - - Console - false - false - - - /ignore:4264 %(AdditionalOptions) - - - - - /DSEND_TELEMETRY %(AdditionalOptions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - Create - Create - - - - - - - - {311e866d-8b93-4609-a691-265941fee101} - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see https://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters deleted file mode 100644 index d05aca0b..00000000 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ /dev/null @@ -1,223 +0,0 @@ - - - - - {1daab7c4-63f6-4266-a259-f34acad66d09} - - - {8d4edf06-c312-4312-978a-b6c2beb8295a} - - - {0184f727-b8aa-4af8-a699-63f1b56e7853} - - - - - - - - - - - - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - DataLoaders - - - DataLoaders - - - DataLoaders - - - - - - - - - - - - - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - Common\Automation - - - DataLoaders - - - DataLoaders - - - DataLoaders - - - DataLoaders - - - DataLoaders - - - Common - - - - - DataLoaders - - - - \ No newline at end of file diff --git a/src/CalcViewModel/Common/AlwaysSelectedCollectionView.h b/src/CalcViewModel/Common/AlwaysSelectedCollectionView.h deleted file mode 100644 index 57e1d74e..00000000 --- a/src/CalcViewModel/Common/AlwaysSelectedCollectionView.h +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace Common - { - ref class AlwaysSelectedCollectionView sealed : public Windows::UI::Xaml::DependencyObject, public Windows::UI::Xaml::Data::ICollectionView - { - internal : AlwaysSelectedCollectionView(Windows::UI::Xaml::Interop::IBindableVector ^ source) - : m_currentPosition(-1) - { - m_source = source; - - Windows::UI::Xaml::Interop::IBindableObservableVector ^ observable = - dynamic_cast(source); - if (observable) - { - observable->VectorChanged += ref new Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler( - this, &AlwaysSelectedCollectionView::OnSourceBindableVectorChanged); - } - } - - private: - // ICollectionView - // Not implemented methods - virtual WF::IAsyncOperation< - Windows::UI::Xaml::Data::LoadMoreItemsResult> ^ LoadMoreItemsAsync(unsigned int) = Windows::UI::Xaml::Data::ICollectionView::LoadMoreItemsAsync - { - throw ref new Platform::NotImplementedException(); - } - virtual bool MoveCurrentToFirst() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToFirst - { - throw ref new Platform::NotImplementedException(); - } - virtual bool MoveCurrentToLast() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToLast - { - throw ref new Platform::NotImplementedException(); - } - virtual bool MoveCurrentToNext() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToNext - { - throw ref new Platform::NotImplementedException(); - } - virtual bool MoveCurrentToPrevious() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPrevious - { - throw ref new Platform::NotImplementedException(); - } - property Windows::Foundation::Collections::IObservableVector ^ CollectionGroups { - virtual Windows::Foundation::Collections::IObservableVector< - Platform::Object ^> ^ get() = Windows::UI::Xaml::Data::ICollectionView::CollectionGroups::get - { - return ref new Platform::Collections::Vector(); - } - } property bool HasMoreItems - { - virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::HasMoreItems::get - { - return false; - } - } - - // Implemented methods - virtual bool MoveCurrentTo(Platform::Object ^ item) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentTo - { - if (item) - { - unsigned int newCurrentPosition = 0; - bool result = m_source->IndexOf(item, &newCurrentPosition); - if (result) - { - m_currentPosition = newCurrentPosition; - m_currentChanged(this, nullptr); - return true; - } - } - - // The item is not in the collection - // We're going to schedule a call back later so we - // restore the selection to the way we wanted it to begin with - if (m_currentPosition >= 0 && m_currentPosition < static_cast(m_source->Size)) - { - this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this]() { - m_currentChanged(this, nullptr); - })); - } - return false; - } - - virtual bool MoveCurrentToPosition(int index) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPosition - { - if (index < 0 || index >= static_cast(m_source->Size)) - { - return false; - } - - m_currentPosition = index; - m_currentChanged(this, nullptr); - return true; - } - - property Platform::Object^ CurrentItem - { - virtual Platform::Object^ get() = Windows::UI::Xaml::Data::ICollectionView::CurrentItem::get - { - if (m_currentPosition >= 0 && m_currentPosition < static_cast(m_source->Size)) - { - return m_source->GetAt(m_currentPosition); - } - return nullptr; - } - } - - property int CurrentPosition - { - virtual int get() = Windows::UI::Xaml::Data::ICollectionView::CurrentPosition::get - { - return m_currentPosition; - } - } - - property bool IsCurrentAfterLast - { - virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentAfterLast::get - { - return m_currentPosition >= static_cast(m_source->Size); - } - } - - property bool IsCurrentBeforeFirst - { - virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentBeforeFirst::get - { - return m_currentPosition < 0; - } - } - - event WF::EventHandler^ CurrentChanged - { - virtual WF::EventRegistrationToken add(WF::EventHandler^ handler) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanged::add - { - return m_currentChanged += handler; - } - virtual void remove(WF::EventRegistrationToken token) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanged::remove - { - m_currentChanged -= token; - } - } - event Windows::UI::Xaml::Data::CurrentChangingEventHandler^ CurrentChanging - { - virtual WF::EventRegistrationToken add(Windows::UI::Xaml::Data::CurrentChangingEventHandler^ handler) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanging::add - { - return m_currentChanging += handler; - } - virtual void remove(WF::EventRegistrationToken token) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanging::remove - { - m_currentChanging -= token; - } - } - - // IVector - // Not implemented methods - virtual void Append(Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector::Append - { - throw ref new Platform::NotImplementedException(); - } - virtual void Clear() = Windows::Foundation::Collections::IVector::Clear - { - throw ref new Platform::NotImplementedException(); - } - virtual unsigned int GetMany( - unsigned int /*startIndex*/, - Platform::WriteOnlyArray ^ /*items*/) = Windows::Foundation::Collections::IVector::GetMany - { - throw ref new Platform::NotImplementedException(); - } - virtual Windows::Foundation::Collections::IVectorView ^ GetView() = Windows::Foundation::Collections::IVector< - Platform::Object ^>::GetView - { - throw ref new Platform::NotImplementedException(); - } - virtual void InsertAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector::InsertAt - { - throw ref new Platform::NotImplementedException(); - } - virtual void RemoveAt(unsigned int /*index*/) = Windows::Foundation::Collections::IVector::RemoveAt - { - throw ref new Platform::NotImplementedException(); - } - virtual void RemoveAtEnd() = Windows::Foundation::Collections::IVector::RemoveAtEnd - { - throw ref new Platform::NotImplementedException(); - } - virtual void - ReplaceAll(const Platform::Array ^ /*items*/) = Windows::Foundation::Collections::IVector::ReplaceAll - { - throw ref new Platform::NotImplementedException(); - } - virtual void SetAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector::SetAt - { - throw ref new Platform::NotImplementedException(); - } - - // Implemented methods - virtual Platform::Object ^ GetAt(unsigned int index) = Windows::Foundation::Collections::IVector::GetAt - { - return m_source->GetAt(index); - } - - virtual bool IndexOf(Platform::Object ^ item, unsigned int* index) = Windows::Foundation::Collections::IVector::IndexOf - { - return m_source->IndexOf(item, index); - } - - property unsigned int Size - { - virtual unsigned int get() = Windows::Foundation::Collections::IVector::Size::get - { - return m_source->Size; - } - } - - // IObservableVector - event Windows::Foundation::Collections::VectorChangedEventHandler^ VectorChanged - { - virtual WF::EventRegistrationToken add(Windows::Foundation::Collections::VectorChangedEventHandler^ handler) = Windows::Foundation::Collections::IObservableVector::VectorChanged::add - { - return m_vectorChanged += handler; - } - virtual void remove(WF::EventRegistrationToken token) = Windows::Foundation::Collections::IObservableVector::VectorChanged::remove - { - m_vectorChanged -= token; - } - } - - // IIterable - // Not implemented - virtual Windows::Foundation::Collections::IIterator^ First() = Windows::Foundation::Collections::IIterable::First - { - throw ref new Platform::NotImplementedException(); - } - - // Event handlers - void OnSourceBindableVectorChanged(Windows::UI::Xaml::Interop::IBindableObservableVector ^ source, Platform::Object ^ e) - { - Windows::Foundation::Collections::IVectorChangedEventArgs ^ args = safe_cast(e); - m_vectorChanged(this, args); - } - - Windows::UI::Xaml::Interop::IBindableVector ^ m_source; - int m_currentPosition; - event WF::EventHandler ^ m_currentChanged; - event Windows::UI::Xaml::Data::CurrentChangingEventHandler ^ m_currentChanging; - event Windows::Foundation::Collections::VectorChangedEventHandler ^ m_vectorChanged; - }; - - public - ref class AlwaysSelectedCollectionViewConverter sealed : public Windows::UI::Xaml::Data::IValueConverter - { - public: - AlwaysSelectedCollectionViewConverter() - { - } - - private: - virtual Platform::Object - ^ Convert( - Platform::Object ^ value, - Windows::UI::Xaml::Interop::TypeName /*targetType*/, - Platform::Object ^ /*parameter*/, - Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert - { - auto result = dynamic_cast(value); - if (result) - { - return ref new AlwaysSelectedCollectionView(result); - } - return Windows::UI::Xaml::DependencyProperty::UnsetValue; // Can't convert - } - - virtual Platform::Object - ^ ConvertBack( - Platform::Object ^ /*value*/, - Windows::UI::Xaml::Interop::TypeName /*targetType*/, - Platform::Object ^ /*parameter*/, - Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack - { - return Windows::UI::Xaml::DependencyProperty::UnsetValue; - } - }; - } -} diff --git a/src/CalcViewModel/Common/AppResourceProvider.cpp b/src/CalcViewModel/Common/AppResourceProvider.cpp deleted file mode 100644 index a75a375f..00000000 --- a/src/CalcViewModel/Common/AppResourceProvider.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "AppResourceProvider.h" - -using namespace Platform; -using namespace Windows::ApplicationModel::Resources; -using namespace CalculatorApp; - -AppResourceProvider::AppResourceProvider() -{ - m_stringResLoader = ResourceLoader::GetForViewIndependentUse(); - m_cEngineStringResLoader = ResourceLoader::GetForViewIndependentUse(L"CEngineStrings"); -} - -AppResourceProvider& AppResourceProvider::GetInstance() -{ - static AppResourceProvider s_instance; - return s_instance; -} - -String ^ AppResourceProvider::GetResourceString(_In_ String ^ key) -{ - return m_stringResLoader->GetString(key); -} - -String ^ AppResourceProvider::GetCEngineString(_In_ String ^ key) -{ - return m_cEngineStringResLoader->GetString(key); -} diff --git a/src/CalcViewModel/Common/AppResourceProvider.h b/src/CalcViewModel/Common/AppResourceProvider.h deleted file mode 100644 index 8876fb91..00000000 --- a/src/CalcViewModel/Common/AppResourceProvider.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - class AppResourceProvider - { - public: - static AppResourceProvider& GetInstance(); - Platform::String ^ GetResourceString(_In_ Platform::String ^ key); - Platform::String ^ GetCEngineString(_In_ Platform::String ^ key); - - private: - AppResourceProvider(); - Windows::ApplicationModel::Resources::ResourceLoader ^ m_stringResLoader; - Windows::ApplicationModel::Resources::ResourceLoader ^ m_cEngineStringResLoader; - }; -} diff --git a/src/CalcViewModel/Common/Automation/INarratorAnnouncementHost.h b/src/CalcViewModel/Common/Automation/INarratorAnnouncementHost.h deleted file mode 100644 index 9f947f41..00000000 --- a/src/CalcViewModel/Common/Automation/INarratorAnnouncementHost.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "NarratorAnnouncement.h" - -// Declaration of the INarratorAnnouncementHost interface. -// This interface exists to hide the concrete announcement host -// being used. Depending on the version of the OS the app is running on, -// the app may need a host that uses LiveRegionChanged or RaiseNotification. - -namespace CalculatorApp::Common::Automation -{ -public - interface class INarratorAnnouncementHost - { - public: - // Is the host available on this OS. - bool IsHostAvailable(); - - // Make a new instance of a concrete host. - INarratorAnnouncementHost ^ MakeHost(); - - // Make an announcement using the concrete host's preferred method. - void Announce(NarratorAnnouncement ^ announcement); - }; -} diff --git a/src/CalcViewModel/Common/Automation/LiveRegionHost.cpp b/src/CalcViewModel/Common/Automation/LiveRegionHost.cpp deleted file mode 100644 index 0df3a96c..00000000 --- a/src/CalcViewModel/Common/Automation/LiveRegionHost.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "LiveRegionHost.h" - -using namespace CalculatorApp::Common::Automation; -using namespace Windows::UI::Xaml::Automation; -using namespace Windows::UI::Xaml::Automation::Peers; -using namespace Windows::UI::Xaml::Controls; - -LiveRegionHost::LiveRegionHost() - : m_host(nullptr) -{ -} - -bool LiveRegionHost::IsHostAvailable() -{ - // LiveRegion is always available. - return true; -} - -INarratorAnnouncementHost ^ LiveRegionHost::MakeHost() -{ - return ref new LiveRegionHost(); -} - -void LiveRegionHost::Announce(NarratorAnnouncement ^ announcement) -{ - if (m_host == nullptr) - { - m_host = ref new TextBlock(); - AutomationProperties::SetLiveSetting(m_host, AutomationLiveSetting::Assertive); - } - - AutomationProperties::SetName(m_host, announcement->Announcement); - AutomationPeer ^ peer = FrameworkElementAutomationPeer::FromElement(m_host); - if (peer != nullptr) - { - peer->RaiseAutomationEvent(AutomationEvents::LiveRegionChanged); - } -} diff --git a/src/CalcViewModel/Common/Automation/LiveRegionHost.h b/src/CalcViewModel/Common/Automation/LiveRegionHost.h deleted file mode 100644 index fef7c714..00000000 --- a/src/CalcViewModel/Common/Automation/LiveRegionHost.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "INarratorAnnouncementHost.h" - -// Declaration of the LiveRegionHost class. -// This class announces NarratorAnnouncements using the LiveRegionChanged event. -// This event is unreliable and should be deprecated in favor of the new -// RaiseNotification API in RS3. - -namespace CalculatorApp::Common::Automation -{ - // This class exists so that the app can run on RS2 and use LiveRegions - // to host notifications on those builds. - // When the app switches to min version RS3, this class can be removed - // and the app will switch to using the Notification API. - // TODO - MSFT 12735088 -public - ref class LiveRegionHost sealed : public INarratorAnnouncementHost - { - public: - LiveRegionHost(); - - virtual bool IsHostAvailable(); - virtual INarratorAnnouncementHost ^ MakeHost(); - - virtual void Announce(NarratorAnnouncement ^ announcement); - - private: - Windows::UI::Xaml::UIElement ^ m_host; - }; -} diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp b/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp deleted file mode 100644 index 5b6d99bd..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NarratorAnnouncement.h" - -using namespace CalculatorApp::Common::Automation; -using namespace Platform; - -namespace CalculatorApp::Common::Automation -{ - namespace CalculatorActivityIds - { - StringReference DisplayUpdated(L"DisplayUpdated"); - StringReference MaxDigitsReached(L"MaxDigitsReached"); - StringReference MemoryCleared(L"MemoryCleared"); - StringReference MemoryItemChanged(L"MemorySlotChanged"); - StringReference MemoryItemAdded(L"MemorySlotAdded"); - StringReference HistoryCleared(L"HistoryCleared"); - StringReference CategoryNameChanged(L"CategoryNameChanged"); - StringReference UpdateCurrencyRates(L"UpdateCurrencyRates"); - StringReference DisplayCopied(L"DisplayCopied"); - StringReference OpenParenthesisCountChanged(L"OpenParenthesisCountChanged"); - StringReference NoParenthesisAdded(L"NoParenthesisAdded"); - } -} - -NarratorAnnouncement::NarratorAnnouncement( - String ^ announcement, - String ^ activityId, - AutomationNotificationKind kind, - AutomationNotificationProcessing processing) - : m_announcement(announcement) - , m_activityId(activityId) - , m_kind(kind) - , m_processing(processing) -{ -} - -String ^ NarratorAnnouncement::Announcement::get() -{ - return m_announcement; -} - -String ^ NarratorAnnouncement::ActivityId::get() -{ - return m_activityId; -} - -AutomationNotificationKind NarratorAnnouncement::Kind::get() -{ - return m_kind; -} - -AutomationNotificationProcessing NarratorAnnouncement::Processing::get() -{ - return m_processing; -} - -bool NarratorAnnouncement::IsValid(NarratorAnnouncement ^ announcement) -{ - return announcement != nullptr && announcement->Announcement != nullptr && !announcement->Announcement->IsEmpty(); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetDisplayUpdatedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::DisplayUpdated, AutomationNotificationKind::Other, AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::MaxDigitsReached, AutomationNotificationKind::Other, AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetMemoryClearedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::MemoryCleared, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetMemoryItemChangedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::MemoryItemChanged, AutomationNotificationKind::ActionCompleted, AutomationNotificationProcessing::MostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetMemoryItemAddedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::MemoryItemAdded, AutomationNotificationKind::ItemAdded, AutomationNotificationProcessing::MostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetHistoryClearedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::HistoryCleared, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::MostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetCategoryNameChangedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, - CalculatorActivityIds::CategoryNameChanged, - AutomationNotificationKind::ActionCompleted, - AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, - CalculatorActivityIds::UpdateCurrencyRates, - AutomationNotificationKind::ActionCompleted, - AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetDisplayCopiedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, CalculatorActivityIds::DisplayCopied, AutomationNotificationKind::ActionCompleted, AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetOpenParenthesisCountChangedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, - CalculatorActivityIds::OpenParenthesisCountChanged, - AutomationNotificationKind::ActionCompleted, - AutomationNotificationProcessing::ImportantMostRecent); -} - -NarratorAnnouncement ^ CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(String ^ announcement) -{ - return ref new NarratorAnnouncement( - announcement, - CalculatorActivityIds::NoParenthesisAdded, - AutomationNotificationKind::ActionCompleted, - AutomationNotificationProcessing::ImportantMostRecent); -} diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h b/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h deleted file mode 100644 index c4c0c526..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp::Common::Automation -{ - // These enum types are copied from the types available in - // Windows::UI::Xaml::Automation::Peers in the RS3 SDK. - // When this app switches to min version RS3, these custom - // enums should be removed and the Windows types should be used - // instead. - // TODO - MSFT 12735088 -public - enum class AutomationNotificationKind - { - ItemAdded = 0, - ItemRemoved = 1, - ActionCompleted = 2, - ActionAborted = 3, - Other = 4 - }; - -public - enum class AutomationNotificationProcessing - { - ImportantAll = 0, - ImportantMostRecent = 1, - All = 2, - MostRecent = 3, - CurrentThenMostRecent = 4 - }; - -public - ref class NarratorAnnouncement sealed - { - public: - property Platform::String - ^ Announcement { Platform::String ^ get(); } - - property Platform::String - ^ ActivityId { Platform::String ^ get(); } - - property AutomationNotificationKind Kind - { - AutomationNotificationKind get(); - } - - property AutomationNotificationProcessing Processing - { - AutomationNotificationProcessing get(); - } - - static bool IsValid(NarratorAnnouncement ^ announcement); - - private: - // Make CalculatorAnnouncement a friend class so it is the only - // class that can access the private constructor. - friend class CalculatorAnnouncement; - - NarratorAnnouncement( - Platform::String ^ announcement, - Platform::String ^ activityId, - AutomationNotificationKind kind, - AutomationNotificationProcessing processing); - - Platform::String ^ m_announcement; - Platform::String ^ m_activityId; - AutomationNotificationKind m_kind; - AutomationNotificationProcessing m_processing; - }; - - // CalculatorAnnouncement is intended to contain only static methods - // that return announcements made for the Calculator app. - class CalculatorAnnouncement - { - public: - static NarratorAnnouncement ^ GetDisplayUpdatedAnnouncement(Platform::String ^ announcement); - static NarratorAnnouncement ^ GetMaxDigitsReachedAnnouncement(Platform::String ^ announcement); - - static NarratorAnnouncement ^ GetMemoryClearedAnnouncement(Platform::String ^ announcement); - static NarratorAnnouncement ^ GetMemoryItemChangedAnnouncement(Platform::String ^ announcement); - static NarratorAnnouncement ^ GetMemoryItemAddedAnnouncement(Platform::String ^ announcement); - - static NarratorAnnouncement ^ GetHistoryClearedAnnouncement(Platform::String ^ announcement); - - static NarratorAnnouncement ^ GetCategoryNameChangedAnnouncement(Platform::String ^ announcement); - - static NarratorAnnouncement ^ GetUpdateCurrencyRatesAnnouncement(Platform::String ^ announcement); - - static NarratorAnnouncement ^ GetDisplayCopiedAnnouncement(Platform::String ^ announcement); - - static NarratorAnnouncement ^ GetOpenParenthesisCountChangedAnnouncement(Platform::String ^ announcement); - static NarratorAnnouncement ^ GetNoRightParenthesisAddedAnnouncement(Platform::String ^ announcement); - }; -} diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.cpp b/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.cpp deleted file mode 100644 index a103c7e7..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NarratorAnnouncementHostFactory.h" -#include "NotificationHost.h" -#include "LiveRegionHost.h" - -using namespace CalculatorApp::Common::Automation; -using namespace std; - -INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::s_hostProducer; -vector NarratorAnnouncementHostFactory::s_hosts; - -// This static variable is used only to call the initialization function, to initialize the other static variables. -int NarratorAnnouncementHostFactory::s_init = NarratorAnnouncementHostFactory::Initialize(); -int NarratorAnnouncementHostFactory::Initialize() -{ - RegisterHosts(); - NarratorAnnouncementHostFactory::s_hostProducer = GetHostProducer(); - - return 0; -} - -// For now, there are two type of announcement hosts. -// We'd prefer to use Notification if it's available and fall back to LiveRegion -// if not. The availability of the host depends on the version of the OS the app is running on. -// When the app switches to min version RS3, the LiveRegionHost can be removed and we will always -// use NotificationHost. -// TODO - MSFT 12735088 -void NarratorAnnouncementHostFactory::RegisterHosts() -{ - // The host that will be used is the first available host, - // therefore, order of hosts is important here. - NarratorAnnouncementHostFactory::s_hosts = { ref new NotificationHost(), ref new LiveRegionHost() }; -} - -INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::GetHostProducer() -{ - for (INarratorAnnouncementHost ^ host : NarratorAnnouncementHostFactory::s_hosts) - { - if (host->IsHostAvailable()) - { - return host; - } - } - - assert(false && L"No suitable AnnouncementHost was found."); - return nullptr; -} - -INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::MakeHost() -{ - if (NarratorAnnouncementHostFactory::s_hostProducer == nullptr) - { - assert(false && L"No host producer has been assigned."); - return nullptr; - } - - return NarratorAnnouncementHostFactory::s_hostProducer->MakeHost(); -} diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.h b/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.h deleted file mode 100644 index 4b739a79..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "INarratorAnnouncementHost.h" - -// Declaration of the NarratorAnnouncementHostFactory class. -// This class exists to hide the construction of a concrete INarratorAnnouncementHost. -// Depending on the version of the OS the app is running on, the factory will return -// an announcement host appropriate for that version. - -namespace CalculatorApp::Common::Automation -{ - class NarratorAnnouncementHostFactory - { - public: - static INarratorAnnouncementHost ^ MakeHost(); - - private: - NarratorAnnouncementHostFactory() - { - } - - static int Initialize(); - static void RegisterHosts(); - static INarratorAnnouncementHost ^ GetHostProducer(); - - private: - static int s_init; - static INarratorAnnouncementHost ^ s_hostProducer; - static std::vector s_hosts; - }; -} diff --git a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp deleted file mode 100644 index bc146e68..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// Implementation of the NarratorNotifier class. - -#include "pch.h" -#include "NarratorNotifier.h" -#include "NarratorAnnouncementHostFactory.h" - -using namespace CalculatorApp::Common::Automation; -using namespace Platform; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Automation; -using namespace Windows::UI::Xaml::Automation::Peers; - -DependencyProperty ^ NarratorNotifier::s_announcementProperty; - -NarratorNotifier::NarratorNotifier() -{ - m_announcementHost = NarratorAnnouncementHostFactory::MakeHost(); -} - -void NarratorNotifier::Announce(NarratorAnnouncement ^ announcement) -{ - if (NarratorAnnouncement::IsValid(announcement) && m_announcementHost != nullptr) - { - m_announcementHost->Announce(announcement); - } -} - -void NarratorNotifier::RegisterDependencyProperties() -{ - s_announcementProperty = DependencyProperty::Register( - L"Announcement", // The name of the dependency property. - NarratorAnnouncement::typeid, // The type of the dependency property. - NarratorNotifier::typeid, // The owner of the dependency property. - ref new PropertyMetadata( - nullptr, // Default value of the dependency property. - ref new PropertyChangedCallback(OnAnnouncementChanged))); -} - -void NarratorNotifier::OnAnnouncementChanged(_In_ DependencyObject ^ dependencyObject, _In_ DependencyPropertyChangedEventArgs ^ e) -{ - auto instance = safe_cast(dependencyObject); - if (instance != nullptr) - { - instance->Announce(safe_cast(e->NewValue)); - } -} diff --git a/src/CalcViewModel/Common/Automation/NarratorNotifier.h b/src/CalcViewModel/Common/Automation/NarratorNotifier.h deleted file mode 100644 index 55bed4e7..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorNotifier.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// Declaration of the NarratorNotifier class. - -#pragma once -#include "INarratorAnnouncementHost.h" - -namespace CalculatorApp::Common::Automation -{ -public - ref class NarratorNotifier sealed : public Windows::UI::Xaml::DependencyObject - { - public: - NarratorNotifier(); - - void Announce(NarratorAnnouncement ^ announcement); - - property NarratorAnnouncement^ Announcement - { - NarratorAnnouncement^ get() { return GetAnnouncement(this); } - void set(NarratorAnnouncement^ value) - { - SetAnnouncement(this, value); - } - } - - static void RegisterDependencyProperties(); - - static property Windows::UI::Xaml::DependencyProperty - ^ AnnouncementProperty { Windows::UI::Xaml::DependencyProperty ^ get() { return s_announcementProperty; } } - - static NarratorAnnouncement - ^ GetAnnouncement( - Windows::UI::Xaml::DependencyObject ^ element) { return safe_cast(element->GetValue(s_announcementProperty)); } - - static void SetAnnouncement(Windows::UI::Xaml::DependencyObject ^ element, NarratorAnnouncement ^ value) - { - element->SetValue(s_announcementProperty, value); - } - - private: - static void OnAnnouncementChanged( - _In_ Windows::UI::Xaml::DependencyObject ^ dependencyObject, - _In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ eventArgs); - - static Windows::UI::Xaml::DependencyProperty ^ s_announcementProperty; - - private: - INarratorAnnouncementHost ^ m_announcementHost; - }; -} diff --git a/src/CalcViewModel/Common/Automation/NotificationHost.cpp b/src/CalcViewModel/Common/Automation/NotificationHost.cpp deleted file mode 100644 index 92bf846e..00000000 --- a/src/CalcViewModel/Common/Automation/NotificationHost.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NotificationHost.h" - -using namespace CalculatorApp::Common::Automation; -using namespace Windows::Foundation::Metadata; -using namespace Windows::UI::Xaml::Automation; -using namespace Windows::UI::Xaml::Automation::Peers; -using namespace Windows::UI::Xaml::Controls; - -NotificationHost::NotificationHost() - : m_host(nullptr) -{ -} - -bool NotificationHost::IsHostAvailable() -{ - return ApiInformation::IsMethodPresent(L"Windows.UI.Xaml.Automation.Peers.AutomationPeer", L"RaiseNotificationEvent"); -} - -INarratorAnnouncementHost ^ NotificationHost::MakeHost() -{ - return ref new NotificationHost(); -} - -void NotificationHost::Announce(NarratorAnnouncement ^ announcement) -{ - if (m_host == nullptr) - { - m_host = ref new TextBlock(); - } - - auto peer = FrameworkElementAutomationPeer::FromElement(m_host); - if (peer != nullptr) - { - peer->RaiseNotificationEvent( - GetWindowsNotificationKind(announcement->Kind), - GetWindowsNotificationProcessing(announcement->Processing), - announcement->Announcement, - announcement->ActivityId); - } -} - -StandardPeers::AutomationNotificationKind NotificationHost::GetWindowsNotificationKind(CustomPeers::AutomationNotificationKind customKindType) -{ - switch (customKindType) - { - case CustomPeers::AutomationNotificationKind::ItemAdded: - return StandardPeers::AutomationNotificationKind::ItemAdded; - - case CustomPeers::AutomationNotificationKind::ItemRemoved: - return StandardPeers::AutomationNotificationKind::ItemRemoved; - - case CustomPeers::AutomationNotificationKind::ActionCompleted: - return StandardPeers::AutomationNotificationKind::ActionCompleted; - - case CustomPeers::AutomationNotificationKind::ActionAborted: - return StandardPeers::AutomationNotificationKind::ActionAborted; - - case CustomPeers::AutomationNotificationKind::Other: - return StandardPeers::AutomationNotificationKind::Other; - - default: - assert(false && L"Unexpected AutomationNotificationKind"); - } - - return StandardPeers::AutomationNotificationKind::Other; -} - -StandardPeers::AutomationNotificationProcessing -NotificationHost::GetWindowsNotificationProcessing(CustomPeers::AutomationNotificationProcessing customProcessingType) -{ - switch (customProcessingType) - { - case CustomPeers::AutomationNotificationProcessing::ImportantAll: - return StandardPeers::AutomationNotificationProcessing::ImportantAll; - - case CustomPeers::AutomationNotificationProcessing::ImportantMostRecent: - return StandardPeers::AutomationNotificationProcessing::ImportantMostRecent; - - case CustomPeers::AutomationNotificationProcessing::All: - return StandardPeers::AutomationNotificationProcessing::All; - - case CustomPeers::AutomationNotificationProcessing::MostRecent: - return StandardPeers::AutomationNotificationProcessing::MostRecent; - - case CustomPeers::AutomationNotificationProcessing::CurrentThenMostRecent: - return StandardPeers::AutomationNotificationProcessing::CurrentThenMostRecent; - - default: - assert(false && L"Unexpected AutomationNotificationProcessing"); - } - - return StandardPeers::AutomationNotificationProcessing::ImportantMostRecent; -} diff --git a/src/CalcViewModel/Common/Automation/NotificationHost.h b/src/CalcViewModel/Common/Automation/NotificationHost.h deleted file mode 100644 index d0a929c6..00000000 --- a/src/CalcViewModel/Common/Automation/NotificationHost.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "INarratorAnnouncementHost.h" - -// Declaration of the NotificationHost class. -// This class announces NarratorAnnouncements using the RaiseNotification API -// available in RS3. - -namespace CalculatorApp::Common::Automation -{ -public - ref class NotificationHost sealed : public INarratorAnnouncementHost - { - public: - NotificationHost(); - - virtual bool IsHostAvailable(); - virtual INarratorAnnouncementHost ^ MakeHost(); - - virtual void Announce(NarratorAnnouncement ^ announcement); - - private: - static Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind - GetWindowsNotificationKind(CalculatorApp::Common::Automation::AutomationNotificationKind customKindType); - - static Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing - GetWindowsNotificationProcessing(CalculatorApp::Common::Automation::AutomationNotificationProcessing customProcessingType); - - private: - Windows::UI::Xaml::UIElement ^ m_host; - }; -} diff --git a/src/CalcViewModel/Common/BindableBase.cpp b/src/CalcViewModel/Common/BindableBase.cpp deleted file mode 100644 index ccba7985..00000000 --- a/src/CalcViewModel/Common/BindableBase.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "BindableBase.h" - -using namespace CalculatorApp::Common; - -using namespace Platform; -using namespace Windows::UI::Xaml::Data; - -/// -/// Notifies listeners that a property value has changed. -/// -/// Name of the property used to notify listeners. -void BindableBase::OnPropertyChanged(String ^ propertyName) -{ - PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName)); -} - -Windows::UI::Xaml::Data::ICustomProperty ^ BindableBase::GetCustomProperty(Platform::String ^ name) -{ - return nullptr; -} - -Windows::UI::Xaml::Data::ICustomProperty ^ BindableBase::GetIndexedProperty(Platform::String ^ name, Windows::UI::Xaml::Interop::TypeName type) -{ - return nullptr; -} - -Platform::String ^ BindableBase::GetStringRepresentation() -{ - return this->ToString(); -} diff --git a/src/CalcViewModel/Common/BindableBase.h b/src/CalcViewModel/Common/BindableBase.h deleted file mode 100644 index d1f958f5..00000000 --- a/src/CalcViewModel/Common/BindableBase.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace Common - { - /// - /// Implementation of to simplify models. - /// - [Windows::Foundation::Metadata::WebHostHidden] public ref class BindableBase : Windows::UI::Xaml::DependencyObject, - Windows::UI::Xaml::Data::INotifyPropertyChanged, - Windows::UI::Xaml::Data::ICustomPropertyProvider - { - public: - virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; - - public: - // ICustomPropertyProvider - virtual Windows::UI::Xaml::Data::ICustomProperty ^ GetCustomProperty(Platform::String ^ name); - virtual Windows::UI::Xaml::Data::ICustomProperty ^ GetIndexedProperty(Platform::String ^ name, Windows::UI::Xaml::Interop::TypeName type); - virtual Platform::String ^ GetStringRepresentation(); - - property Windows::UI::Xaml::Interop::TypeName Type - { - virtual Windows::UI::Xaml::Interop::TypeName get() - { - return this->GetType(); - } - } - - protected: - virtual void OnPropertyChanged(Platform::String ^ propertyName); - }; - } -} diff --git a/src/CalcViewModel/Common/CalculatorButtonPressedEventArgs.cpp b/src/CalcViewModel/Common/CalculatorButtonPressedEventArgs.cpp deleted file mode 100644 index 76c0d4c0..00000000 --- a/src/CalcViewModel/Common/CalculatorButtonPressedEventArgs.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "CalculatorButtonPressedEventArgs.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace Platform; - -NumbersAndOperatorsEnum CalculatorButtonPressedEventArgs::GetOperationFromCommandParameter(_In_ Object ^ commandParameter) -{ - auto eventArgs = dynamic_cast(commandParameter); - if (eventArgs != nullptr) - { - return eventArgs->Operation; - } - else - { - return safe_cast(commandParameter); - } -} - -String ^ CalculatorButtonPressedEventArgs::GetAuditoryFeedbackFromCommandParameter(_In_ Object ^ commandParameter) -{ - auto eventArgs = dynamic_cast(commandParameter); - if (eventArgs != nullptr) - { - return eventArgs->AuditoryFeedback; - } - else - { - return nullptr; - } -} diff --git a/src/CalcViewModel/Common/CalculatorButtonPressedEventArgs.h b/src/CalcViewModel/Common/CalculatorButtonPressedEventArgs.h deleted file mode 100644 index 27624987..00000000 --- a/src/CalcViewModel/Common/CalculatorButtonPressedEventArgs.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalculatorButtonUser.h" -#include "Utils.h" - -namespace CalculatorApp -{ - namespace Common - { - public - ref class CalculatorButtonPressedEventArgs sealed - { - public: - PROPERTY_R(Platform::String ^, AuditoryFeedback); - PROPERTY_R(CalculatorApp::NumbersAndOperatorsEnum, Operation); - - CalculatorButtonPressedEventArgs(Platform::String ^ feedback, CalculatorApp::NumbersAndOperatorsEnum operation) - : m_AuditoryFeedback(feedback) - , m_Operation(operation) - { - } - - static CalculatorApp::NumbersAndOperatorsEnum GetOperationFromCommandParameter(_In_ Platform::Object ^ commandParameter); - static Platform::String ^ GetAuditoryFeedbackFromCommandParameter(_In_ Platform::Object ^ commandParameter); - }; - } -} diff --git a/src/CalcViewModel/Common/CalculatorButtonUser.h b/src/CalcViewModel/Common/CalculatorButtonUser.h deleted file mode 100644 index 19fa4044..00000000 --- a/src/CalcViewModel/Common/CalculatorButtonUser.h +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/Command.h" - -namespace CalculatorApp -{ - namespace CM = CalculationManager; - -public - enum class NumbersAndOperatorsEnum - { - Zero = (int)CM::Command::Command0, - One = (int)CM::Command::Command1, - Two = (int)CM::Command::Command2, - Three = (int)CM::Command::Command3, - Four = (int)CM::Command::Command4, - Five = (int)CM::Command::Command5, - Six = (int)CM::Command::Command6, - Seven = (int)CM::Command::Command7, - Eight = (int)CM::Command::Command8, - Nine = (int)CM::Command::Command9, - Add = (int)CM::Command::CommandADD, - Subtract = (int)CM::Command::CommandSUB, - Multiply = (int)CM::Command::CommandMUL, - Divide = (int)CM::Command::CommandDIV, - Invert = (int)CM::Command::CommandREC, - Equals = (int)CM::Command::CommandEQU, - Decimal = (int)CM::Command::CommandPNT, - Sqrt = (int)CM::Command::CommandSQRT, - Percent = (int)CM::Command::CommandPERCENT, - Negate = (int)CM::Command::CommandSIGN, - Backspace = (int)CM::Command::CommandBACK, - ClearEntry = (int)CM::Command::CommandCENTR, - Clear = (int)CM::Command::CommandCLEAR, - Degree = (int)CM::Command::CommandDEG, - Radians = (int)CM::Command::CommandRAD, - Grads = (int)CM::Command::CommandGRAD, - Degrees = (int)CM::Command::CommandDegrees, - OpenParenthesis = (int)CM::Command::CommandOPENP, - CloseParenthesis = (int)CM::Command::CommandCLOSEP, - Pi = (int)CM::Command::CommandPI, - Sin = (int)CM::Command::CommandSIN, - Cos = (int)CM::Command::CommandCOS, - Tan = (int)CM::Command::CommandTAN, - Factorial = (int)CM::Command::CommandFAC, - XPower2 = (int)CM::Command::CommandSQR, - Mod = (int)CM::Command::CommandMOD, - FToE = (int)CM::Command::CommandFE, - LogBaseE = (int)CM::Command::CommandLN, - InvSin = (int)CM::Command::CommandASIN, - InvCos = (int)CM::Command::CommandACOS, - InvTan = (int)CM::Command::CommandATAN, - LogBase10 = (int)CM::Command::CommandLOG, - XPowerY = (int)CM::Command::CommandPWR, - YRootX = (int)CM::Command::CommandROOT, - TenPowerX = (int)CM::Command::CommandPOW10, - EPowerX = (int)CM::Command::CommandPOWE, - Exp = (int)CM::Command::CommandEXP, - IsScientificMode = (int)CM::Command::ModeScientific, - 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, - Or = (int)CM::Command::CommandOR, - Lsh = (int)CM::Command::CommandLSHF, - Rsh = (int)CM::Command::CommandRSHF, - Xor = (int)CM::Command::CommandXor, - Not = (int)CM::Command::CommandNot, - A = (int)CM::Command::CommandA, - B = (int)CM::Command::CommandB, - C = (int)CM::Command::CommandC, - D = (int)CM::Command::CommandD, - E = (int)CM::Command::CommandE, - F = (int)CM::Command::CommandF, - Memory, // This is the memory button. Doesn't have a direct mapping to the CalcEngine. - Sinh = (int)CM::Command::CommandSINH, - Cosh = (int)CM::Command::CommandCOSH, - Tanh = (int)CM::Command::CommandTANH, - 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, - - BINSTART = (int)CM::Command::CommandBINEDITSTART, - BINPOS0 = (int)CM::Command::CommandBINPOS0, - BINPOS1 = (int)CM::Command::CommandBINPOS1, - BINPOS2 = (int)CM::Command::CommandBINPOS2, - BINPOS3 = (int)CM::Command::CommandBINPOS3, - BINPOS4 = (int)CM::Command::CommandBINPOS4, - BINPOS5 = (int)CM::Command::CommandBINPOS5, - BINPOS6 = (int)CM::Command::CommandBINPOS6, - BINPOS7 = (int)CM::Command::CommandBINPOS7, - BINPOS8 = (int)CM::Command::CommandBINPOS8, - BINPOS9 = (int)CM::Command::CommandBINPOS9, - BINPOS10 = (int)CM::Command::CommandBINPOS10, - BINPOS11 = (int)CM::Command::CommandBINPOS11, - BINPOS12 = (int)CM::Command::CommandBINPOS12, - BINPOS13 = (int)CM::Command::CommandBINPOS13, - BINPOS14 = (int)CM::Command::CommandBINPOS14, - BINPOS15 = (int)CM::Command::CommandBINPOS15, - BINPOS16 = (int)CM::Command::CommandBINPOS16, - BINPOS17 = (int)CM::Command::CommandBINPOS17, - BINPOS18 = (int)CM::Command::CommandBINPOS18, - BINPOS19 = (int)CM::Command::CommandBINPOS19, - BINPOS20 = (int)CM::Command::CommandBINPOS20, - BINPOS21 = (int)CM::Command::CommandBINPOS21, - BINPOS22 = (int)CM::Command::CommandBINPOS22, - BINPOS23 = (int)CM::Command::CommandBINPOS23, - BINPOS24 = (int)CM::Command::CommandBINPOS24, - BINPOS25 = (int)CM::Command::CommandBINPOS25, - BINPOS26 = (int)CM::Command::CommandBINPOS26, - BINPOS27 = (int)CM::Command::CommandBINPOS27, - BINPOS28 = (int)CM::Command::CommandBINPOS28, - BINPOS29 = (int)CM::Command::CommandBINPOS29, - BINPOS30 = (int)CM::Command::CommandBINPOS30, - BINPOS31 = (int)CM::Command::CommandBINPOS31, - BINPOS32 = (int)CM::Command::CommandBINPOS32, - BINPOS33 = (int)CM::Command::CommandBINPOS33, - BINPOS34 = (int)CM::Command::CommandBINPOS34, - BINPOS35 = (int)CM::Command::CommandBINPOS35, - BINPOS36 = (int)CM::Command::CommandBINPOS36, - BINPOS37 = (int)CM::Command::CommandBINPOS37, - BINPOS38 = (int)CM::Command::CommandBINPOS38, - BINPOS39 = (int)CM::Command::CommandBINPOS39, - BINPOS40 = (int)CM::Command::CommandBINPOS40, - BINPOS41 = (int)CM::Command::CommandBINPOS41, - BINPOS42 = (int)CM::Command::CommandBINPOS42, - BINPOS43 = (int)CM::Command::CommandBINPOS43, - BINPOS44 = (int)CM::Command::CommandBINPOS44, - BINPOS45 = (int)CM::Command::CommandBINPOS45, - BINPOS46 = (int)CM::Command::CommandBINPOS46, - BINPOS47 = (int)CM::Command::CommandBINPOS47, - BINPOS48 = (int)CM::Command::CommandBINPOS48, - BINPOS49 = (int)CM::Command::CommandBINPOS49, - BINPOS50 = (int)CM::Command::CommandBINPOS50, - BINPOS51 = (int)CM::Command::CommandBINPOS51, - BINPOS52 = (int)CM::Command::CommandBINPOS52, - BINPOS53 = (int)CM::Command::CommandBINPOS53, - BINPOS54 = (int)CM::Command::CommandBINPOS54, - BINPOS55 = (int)CM::Command::CommandBINPOS55, - BINPOS56 = (int)CM::Command::CommandBINPOS56, - BINPOS57 = (int)CM::Command::CommandBINPOS57, - BINPOS58 = (int)CM::Command::CommandBINPOS58, - BINPOS59 = (int)CM::Command::CommandBINPOS59, - BINPOS60 = (int)CM::Command::CommandBINPOS60, - 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 - }; - - // This contains list of functions whose usage we are tracelogging -public - enum class FunctionLogEnum - { - Invert = (int)CM::Command::CommandREC, - Sqrt = (int)CM::Command::CommandSQRT, - Percent = (int)CM::Command::CommandPERCENT, - Negate = (int)CM::Command::CommandSIGN, - Degrees = (int)CM::Command::CommandDegrees, - Pi = (int)CM::Command::CommandPI, - Sin = (int)CM::Command::CommandSIN, - Cos = (int)CM::Command::CommandCOS, - Tan = (int)CM::Command::CommandTAN, - Factorial = (int)CM::Command::CommandFAC, - XPower2 = (int)CM::Command::CommandSQR, - Mod = (int)CM::Command::CommandMOD, - FToE = (int)CM::Command::CommandFE, - LogBaseE = (int)CM::Command::CommandLN, - InvSin = (int)CM::Command::CommandASIN, - InvCos = (int)CM::Command::CommandACOS, - InvTan = (int)CM::Command::CommandATAN, - LogBase10 = (int)CM::Command::CommandLOG, - XPowerY = (int)CM::Command::CommandPWR, - YRootX = (int)CM::Command::CommandROOT, - TenPowerX = (int)CM::Command::CommandPOW10, - EPowerX = (int)CM::Command::CommandPOWE, - Exp = (int)CM::Command::CommandEXP, - 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, - Or = (int)CM::Command::CommandOR, - Lsh = (int)CM::Command::CommandLSHF, - Rsh = (int)CM::Command::CommandRSHF, - Xor = (int)CM::Command::CommandXor, - Not = (int)CM::Command::CommandNot, - Sinh = (int)CM::Command::CommandSINH, - Cosh = (int)CM::Command::CommandCOSH, - Tanh = (int)CM::Command::CommandTANH, - InvSinh = (int)CM::Command::CommandASINH, - InvCosh = (int)CM::Command::CommandACOSH, - InvTanh = (int)CM::Command::CommandATANH, - Cube = (int)CM::Command::CommandCUB, - DMS = (int)CM::Command::CommandDMS, - }; -} diff --git a/src/CalcViewModel/Common/CalculatorDisplay.cpp b/src/CalcViewModel/Common/CalculatorDisplay.cpp deleted file mode 100644 index 91892dda..00000000 --- a/src/CalcViewModel/Common/CalculatorDisplay.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// This class provides the concrete implementation for the ICalcDisplay interface -// that is declared in the Calculation Manager Library. -#include "pch.h" -#include "CalculatorDisplay.h" -#include "StandardCalculatorViewModel.h" - -using namespace CalculatorApp; -using namespace CalculationManager; -using namespace std; - -CalculatorDisplay::CalculatorDisplay() -{ -} - -void CalculatorDisplay::SetCallback(Platform::WeakReference callbackReference) -{ - m_callbackReference = callbackReference; -} - -void CalculatorDisplay::SetHistoryCallback(Platform::WeakReference callbackReference) -{ - m_historyCallbackReference = callbackReference; -} - -void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue, _In_ bool isError) -{ - if (m_callbackReference) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->SetPrimaryDisplay(displayStringValue, isError); - } - } -} - -void CalculatorDisplay::SetParenthesisNumber(_In_ unsigned int parenthesisCount) -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->SetParenthesisCount(parenthesisCount); - } - } -} - -void CalculatorDisplay::OnNoRightParenAdded() -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->OnNoRightParenAdded(); - } - } -} - -void CalculatorDisplay::SetIsInError(bool isError) -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->IsInError = isError; - } - } -} - -void CalculatorDisplay::SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands) -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->SetExpressionDisplay(tokens, commands); - } - } -} - -void CalculatorDisplay::SetMemorizedNumbers(_In_ const vector& newMemorizedNumbers) -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->SetMemorizedNumbers(newMemorizedNumbers); - } - } -} - -void CalculatorDisplay::OnHistoryItemAdded(_In_ unsigned int addedItemIndex) -{ - if (m_historyCallbackReference != nullptr) - { - if (auto historyVM = m_historyCallbackReference.Resolve()) - { - historyVM->OnHistoryItemAdded(addedItemIndex); - } - } -} - -void CalculatorDisplay::MaxDigitsReached() -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->OnMaxDigitsReached(); - } - } -} - -void CalculatorDisplay::BinaryOperatorReceived() -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->OnBinaryOperatorReceived(); - } - } -} - -void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory) -{ - if (m_callbackReference != nullptr) - { - if (auto calcVM = m_callbackReference.Resolve()) - { - calcVM->OnMemoryItemChanged(indexOfMemory); - } - } -} diff --git a/src/CalcViewModel/Common/CalculatorDisplay.h b/src/CalcViewModel/Common/CalculatorDisplay.h deleted file mode 100644 index 93865c96..00000000 --- a/src/CalcViewModel/Common/CalculatorDisplay.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/Header Files/ICalcDisplay.h" - -namespace CalculatorApp -{ - // Callback interface to be implemented by the CalculatorManager - class CalculatorDisplay : public ICalcDisplay - { - public: - CalculatorDisplay(); - void SetCallback(Platform::WeakReference callbackReference); - void SetHistoryCallback(Platform::WeakReference callbackReference); - - private: - void SetPrimaryDisplay(_In_ const std::wstring& displayString, _In_ bool isError) override; - void SetIsInError(bool isError) override; - void SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands) override; - void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override; - void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; - void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override; - void OnNoRightParenAdded() override; - void MaxDigitsReached() override; - void BinaryOperatorReceived() override; - void MemoryItemChanged(unsigned int indexOfMemory) override; - - private: - Platform::WeakReference m_callbackReference; - Platform::WeakReference m_historyCallbackReference; - }; -} diff --git a/src/CalcViewModel/Common/ConversionResultTaskHelper.cpp b/src/CalcViewModel/Common/ConversionResultTaskHelper.cpp deleted file mode 100644 index ec90228f..00000000 --- a/src/CalcViewModel/Common/ConversionResultTaskHelper.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "ConversionResultTaskHelper.h" - -using namespace CalculatorApp::Common; -using namespace concurrency; -using namespace std; - -ConversionResultTaskHelper::ConversionResultTaskHelper(unsigned int delay, const function functionToRun) - : m_delay{ delay } - , m_storedFunction{ functionToRun } -{ - auto token = m_cts.get_token(); - auto delayTask = CompleteAfter(delay); - delayTask.then( - [this, token]() { - if (!token.is_canceled()) - { - m_storedFunction(); - } - }, - task_continuation_context::use_current()); -} - -ConversionResultTaskHelper::~ConversionResultTaskHelper() -{ - m_cts.cancel(); -} - -#pragma optimize("", off) -// Creates a task that completes after the specified delay. -// -// Taken from: How to: Create a Task that Completes After a Delay -// https://msdn.microsoft.com/en-us/library/hh873170.aspx -task ConversionResultTaskHelper::CompleteAfter(unsigned int timeout) -{ - co_await winrt::resume_after(winrt::Windows::Foundation::TimeSpan{ std::chrono::duration(timeout) }); -}; -#pragma optimize("", on) diff --git a/src/CalcViewModel/Common/ConversionResultTaskHelper.h b/src/CalcViewModel/Common/ConversionResultTaskHelper.h deleted file mode 100644 index 2fe543c3..00000000 --- a/src/CalcViewModel/Common/ConversionResultTaskHelper.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace Common - { - class ConversionResultTaskHelper - { - public: - ConversionResultTaskHelper(unsigned int delay, const std::function functionToRun); - ~ConversionResultTaskHelper(); - - private: - concurrency::task CompleteAfter(unsigned int timeout); - - unsigned int m_delay; - concurrency::cancellation_token_source m_cts; - const std::function m_storedFunction; - }; - } -} diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp deleted file mode 100644 index ffe91d1b..00000000 --- a/src/CalcViewModel/Common/CopyPasteManager.cpp +++ /dev/null @@ -1,563 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "CopyPasteManager.h" -#include "Common/TraceLogger.h" -#include "Common/LocalizationSettings.h" - -using namespace std; -using namespace concurrency; -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::System; -using namespace Windows::ApplicationModel::DataTransfer; - -String ^ CopyPasteManager::supportedFormats[] = { StandardDataFormats::Text }; - -static constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" }; - -// The below values can not be "constexpr"-ed, -// as both wstring_view and wchar[] can not be concatenated -// [\s\x85] means white-space characters -static const wstring c_wspc = L"[\\s\\x85]*"; -static const wstring c_wspcLParens = c_wspc + L"[(]*" + c_wspc; -static const wstring c_wspcLParenSigned = c_wspc + L"([-+]?[(])*" + c_wspc; -static const wstring c_wspcRParens = c_wspc + L"[)]*" + c_wspc; -static const wstring c_signedDecFloat = L"[-+]?\\d*(\\d|[.])\\d*"; - -// Programmer Mode Integer patterns -// Support digit separators ` (WinDbg/MASM), ' (C++), and _ (C# and other languages) -static const wstring c_hexProgrammerChars = L"([a-f]|[A-F]|\\d)+((_|'|`)([a-f]|[A-F]|\\d)+)*"; -static const wstring c_decProgrammerChars = L"\\d+((_|'|`)\\d+)*"; -static const wstring c_octProgrammerChars = L"[0-7]+((_|'|`)[0-7]+)*"; -static const wstring c_binProgrammerChars = L"[0-1]+((_|'|`)[0-1]+)*"; -static const wstring c_uIntSuffixes = L"[uU]?[lL]{0,2}"; - -// RegEx Patterns used by various modes -static const array standardModePatterns = { wregex(c_wspc + c_signedDecFloat + c_wspc) }; -static const array scientificModePatterns = { - wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_wspcRParens), - wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + L"[e]([+]|[-])+\\d+" + c_wspcRParens) -}; -static const array, 4> programmerModePatterns = { - { // Hex numbers like 5F, 4A0C, 0xa9, 0xFFull, 47CDh - { wregex(c_wspcLParens + L"(0[xX])?" + c_hexProgrammerChars + c_uIntSuffixes + c_wspcRParens), - wregex(c_wspcLParens + c_hexProgrammerChars + L"[hH]?" + c_wspcRParens) }, - // Decimal numbers like -145, 145, 0n145, 123ull etc - { wregex(c_wspcLParens + L"[-+]?" + c_decProgrammerChars + L"[lL]{0,2}" + c_wspcRParens), - wregex(c_wspcLParens + L"(0[nN])?" + c_decProgrammerChars + c_uIntSuffixes + c_wspcRParens) }, - // Octal numbers like 06, 010, 0t77, 0o77, 077ull etc - { wregex(c_wspcLParens + L"(0[otOT])?" + c_octProgrammerChars + c_uIntSuffixes + c_wspcRParens) }, - // Binary numbers like 011010110, 0010110, 10101001, 1001b, 0b1001, 0y1001, 0b1001ull - { wregex(c_wspcLParens + L"(0[byBY])?" + c_binProgrammerChars + c_uIntSuffixes + c_wspcRParens), - wregex(c_wspcLParens + c_binProgrammerChars + L"[bB]?" + c_wspcRParens) } } -}; -static const array unitConverterPatterns = { wregex(c_wspc + L"[-+]?\\d*[.]?\\d*" + c_wspc) }; - -void CopyPasteManager::CopyToClipboard(String ^ stringToCopy) -{ - // Copy the string to the clipboard - auto dataPackage = ref new DataPackage(); - dataPackage->SetText(stringToCopy); - Clipboard::SetContent(dataPackage); -} - -task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) -{ - // Retrieve the text in the clipboard - auto dataPackageView = Clipboard::GetContent(); - - // TODO: Support all formats supported by ClipboardHasText - //-- add support to avoid pasting of expressions like 12 34(as of now we allow 1234) - //-- add support to allow pasting for expressions like .2 , -.2 - //-- add support to allow pasting for expressions like 1.3e12(as of now we allow 1.3e+12) - - return create_task((dataPackageView->GetTextAsync(::StandardDataFormats::Text))) - .then( - [mode, modeType, programmerNumberBase, bitLengthType](String ^ pastedText) { - return ValidatePasteExpression(pastedText, mode, modeType, programmerNumberBase, bitLengthType); - }, - task_continuation_context::use_arbitrary()); -} - -int CopyPasteManager::ClipboardTextFormat() -{ - const auto dataPackageView = Clipboard::GetContent(); - - for (int i = 0; i < RTL_NUMBER_OF(supportedFormats); i++) - { - if (dataPackageView->Contains(supportedFormats[i])) - { - return i; - } - } - return -1; -} - -String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, int programmerNumberBase, int bitLengthType) -{ - return CopyPasteManager::ValidatePasteExpression(pastedText, mode, NavCategory::GetGroupType(mode), programmerNumberBase, bitLengthType); -} - -// return "NoOp" if pastedText is invalid else return pastedText - -String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) -{ - if (pastedText->Length() > MaxPasteableLength) - { - // return NoOp to indicate don't paste anything. - TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"PastedExpressionSizeGreaterThanMaxAllowed", mode, programmerNumberBase, bitLengthType); - return StringReference(PasteErrorString); - } - - wstring pasteExpression = pastedText->Data(); - - // Get english translated expression - String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression); - - // Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333 - pasteExpression = RemoveUnwantedCharsFromWstring(englishString->Data()); - - // If the last character is an = sign, remove it from the pasteExpression to allow evaluating the result on paste. - if (!pasteExpression.empty() && pasteExpression.back() == L'=') - { - pasteExpression = pasteExpression.substr(0, pasteExpression.length() - 1); - } - - // Extract operands from the expression to make regex comparison easy and quick. For whole expression it was taking too much of time. - // Operands vector will have the list of operands in the pasteExpression - vector operands = ExtractOperands(pasteExpression, mode, programmerNumberBase, bitLengthType); - if (operands.empty()) - { - // return NoOp to indicate don't paste anything. - return StringReference(PasteErrorString); - } - - if (modeType == CategoryGroupType::Converter) - { - operands = { pasteExpression }; - } - - // validate each operand with patterns for different modes - if (!ExpressionRegExMatch(operands, mode, modeType, programmerNumberBase, bitLengthType)) - { - TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"InvalidExpressionForPresentMode", mode, programmerNumberBase, bitLengthType); - return StringReference(PasteErrorString); - } - - return ref new String(pastedText->Data()); -} - -vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression, ViewMode mode, int programmerNumberBase, int bitLengthType) -{ - vector operands{}; - size_t lastIndex = 0; - bool haveOperator = false; - bool startExpCounting = false; - bool startOfExpression = true; - bool isPreviousOpenParen = false; - bool isPreviousOperator = false; - - // This will have the exponent length - size_t expLength = 0; - for (size_t i = 0; i < pasteExpression.length(); i++) - { - // if the current character is not a valid one don't process it - if (c_validCharacterSet.find(pasteExpression.at(i)) == wstring_view::npos) - { - continue; - } - - if (operands.size() >= MaxOperandCount) - { - TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"OperandCountGreaterThanMaxCount", mode, programmerNumberBase, bitLengthType); - operands.clear(); - return operands; - } - - if (startExpCounting) - { - if ((pasteExpression.at(i) >= L'0') && (pasteExpression.at(i) <= L'9')) - { - expLength++; - - // to disallow pasting of 1e+12345 as 1e+1234, max exponent that can be pasted is 9999. - if (expLength > MaxExponentLength) - { - TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"ExponentLengthGreaterThanMaxLength", mode, programmerNumberBase, bitLengthType); - operands.clear(); - return operands; - } - } - } - - if ((mode != ViewMode::Programmer) && (pasteExpression.at(i) == L'e')) - { - startExpCounting = true; - } - - if (((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-') || (pasteExpression.at(i) == L'*') || (pasteExpression.at(i) == L'/'))) - { - if ((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-')) - { - // don't break the expression into operands if the encountered character corresponds to sign command(+-) - if (isPreviousOpenParen || startOfExpression || isPreviousOperator - || ((mode != ViewMode::Programmer) && !((i != 0) && (pasteExpression.at(i - 1) != L'e')))) - { - isPreviousOperator = false; - continue; - } - } - - startExpCounting = false; - expLength = 0; - haveOperator = true; - isPreviousOperator = true; - operands.push_back(pasteExpression.substr(lastIndex, i - lastIndex)); - lastIndex = i + 1; - } - else - { - isPreviousOperator = false; - } - - isPreviousOpenParen = (pasteExpression.at(i) == L'('); - startOfExpression = false; - } - - if (!haveOperator) - { - operands.clear(); - operands.push_back(pasteExpression); - } - else - { - operands.push_back(pasteExpression.substr(lastIndex, pasteExpression.length() - 1)); - } - - return operands; -} - -bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) -{ - if (operands.empty()) - { - return false; - } - - vector patterns{}; - - if (mode == ViewMode::Standard) - { - patterns.assign(standardModePatterns.begin(), standardModePatterns.end()); - } - else if (mode == ViewMode::Scientific) - { - patterns.assign(scientificModePatterns.begin(), scientificModePatterns.end()); - } - else if (mode == ViewMode::Programmer) - { - patterns.assign(programmerModePatterns[programmerNumberBase - HexBase].begin(), programmerModePatterns[programmerNumberBase - HexBase].end()); - } - else if (modeType == CategoryGroupType::Converter) - { - patterns.assign(unitConverterPatterns.begin(), unitConverterPatterns.end()); - } - - const auto [maxOperandLength, maxOperandValue] = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType); - bool expMatched = true; - - for (const auto& operand : operands) - { - // Each operand only needs to match one of the available patterns. - bool operandMatched = false; - for (const auto& pattern : patterns) - { - operandMatched = operandMatched || regex_match(operand, pattern); - } - - if (operandMatched) - { - // Remove characters that are valid in the expression but we do not want to include in length calculations - // or which will break conversion from string-to-ULL. - const wstring operandValue = SanitizeOperand(operand); - - // If an operand exceeds the maximum length allowed, break and return. - if (OperandLength(operandValue, mode, modeType, programmerNumberBase) > maxOperandLength) - { - expMatched = false; - break; - } - - // If maxOperandValue is set and the operandValue exceeds it, break and return. - if (maxOperandValue != 0) - { - unsigned long long int operandAsULL = 0; - if (!TryOperandToULL(operandValue, programmerNumberBase, operandAsULL)) - { - // Operand was empty, received invalid_argument, or received out_of_range. Input is invalid. - expMatched = false; - break; - } - - if (operandAsULL > maxOperandValue) - { - expMatched = false; - break; - } - } - } - - expMatched = expMatched && operandMatched; - } - - return expMatched; -} - -pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) -{ - constexpr size_t defaultMaxOperandLength = 0; - constexpr uint64_t defaultMaxValue = 0; - - if (mode == ViewMode::Standard) - { - return make_pair(MaxStandardOperandLength, defaultMaxValue); - } - else if (mode == ViewMode::Scientific) - { - return make_pair(MaxScientificOperandLength, defaultMaxValue); - } - else if (mode == ViewMode::Programmer) - { - unsigned int bitLength = 0; - switch (bitLengthType) - { - case QwordType: - bitLength = 64; - break; - case DwordType: - bitLength = 32; - break; - case WordType: - bitLength = 16; - break; - case ByteType: - bitLength = 8; - break; - } - - double bitsPerDigit = 0; - switch (programmerNumberBase) - { - case BinBase: - bitsPerDigit = log2(2); - break; - case OctBase: - bitsPerDigit = log2(8); - break; - case DecBase: - bitsPerDigit = log2(10); - break; - case HexBase: - bitsPerDigit = log2(16); - break; - } - - unsigned int signBit = (programmerNumberBase == DecBase) ? 1 : 0; - - const auto maxLength = static_cast(ceil((bitLength - signBit) / bitsPerDigit)); - const uint64_t maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit)); - - return make_pair(maxLength, maxValue); - } - else if (modeType == CategoryGroupType::Converter) - { - return make_pair(MaxConverterInputLength, defaultMaxValue); - } - - return make_pair(defaultMaxOperandLength, defaultMaxValue); -} - -wstring CopyPasteManager::SanitizeOperand(const wstring& operand) -{ - wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-', L'+' }; - - return Utils::RemoveUnwantedCharsFromWstring(operand, unWantedChars, static_cast(size(unWantedChars))); -} - -bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, unsigned long long int& result) -{ - result = 0; - - if (operand.length() == 0 || operand.front() == L'-') - { - return false; - } - - int intBase; - switch (numberBase) - { - case HexBase: - intBase = 16; - break; - case OctBase: - intBase = 8; - break; - case BinBase: - intBase = 2; - break; - default: - case DecBase: - intBase = 10; - break; - } - - wstring::size_type size = 0; - try - { - result = stoull(operand, &size, intBase); - return true; - } - catch (const invalid_argument&) - { - // Do nothing - } - catch (const out_of_range&) - { - // Do nothing - } - - return false; -} - -size_t CopyPasteManager::OperandLength(const wstring& operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase) -{ - if (modeType == CategoryGroupType::Converter) - { - return operand.length(); - } - - switch (mode) - { - case ViewMode::Standard: - case ViewMode::Scientific: - return StandardScientificOperandLength(operand); - - case ViewMode::Programmer: - return ProgrammerOperandLength(operand, programmerNumberBase); - - default: - return 0; - } -} - -size_t CopyPasteManager::StandardScientificOperandLength(const wstring& operand) -{ - const bool hasDecimal = operand.find('.') != wstring::npos; - - if (hasDecimal) - { - if (operand.length() >= 2) - { - if ((operand[0] == L'0') && (operand[1] == L'.')) - { - return operand.length() - 2; - } - else - { - return operand.length() - 1; - } - } - } - - return operand.length(); -} - -size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int numberBase) -{ - vector prefixes{}; - vector suffixes{}; - switch (numberBase) - { - case BinBase: - prefixes = { L"0B", L"0Y" }; - suffixes = { L"B" }; - break; - case DecBase: - prefixes = { L"-", L"0N" }; - break; - case OctBase: - prefixes = { L"0T", L"0O" }; - break; - case HexBase: - prefixes = { L"0X" }; - suffixes = { L"H" }; - break; - default: - // No defined prefixes/suffixes - return 0; - } - - // UInt suffixes are common across all modes - const array uintSuffixes = { L"ULL", L"UL", L"LL", L"U", L"L" }; - suffixes.insert(suffixes.end(), uintSuffixes.begin(), uintSuffixes.end()); - - wstring operandUpper = operand; - transform(operandUpper.begin(), operandUpper.end(), operandUpper.begin(), towupper); - - size_t len = operand.length(); - - // Detect if there is a suffix and subtract its length - // Check suffixes first to allow e.g. "0b" to result in length 1 (value 0), rather than length 0 (no value). - for (const auto& suffix : suffixes) - { - if (len < suffix.length()) - { - continue; - } - - if (operandUpper.compare(operandUpper.length() - suffix.length(), suffix.length(), suffix) == 0) - { - len -= suffix.length(); - break; - } - } - - // Detect if there is a prefix and subtract its length - for (const auto& prefix : prefixes) - { - if (len < prefix.length()) - { - continue; - } - - if (operandUpper.compare(0, prefix.length(), prefix) == 0) - { - len -= prefix.length(); - break; - } - } - - return len; -} - -// return wstring after removing characters like space, comma, double quotes, and monetary prefix currency symbols supported by the Windows keyboard: -// yen or yuan(¥) - 165 -// unspecified currency sign(¤) - 164 -// Ghanaian cedi(₵) - 8373 -// dollar or peso($) - 36 -// colón(₡) - 8353 -// won(₩) - 8361 -// shekel(₪) - 8362 -// naira(₦) - 8358 -// Indian rupee(₹) - 8377 -// pound(£) - 163 -// euro(€) - 8364 -wstring CopyPasteManager::RemoveUnwantedCharsFromWstring(const wstring& input) -{ - wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237 }; - return Utils::RemoveUnwantedCharsFromWstring(input, unWantedChars, 18); -} diff --git a/src/CalcViewModel/Common/CopyPasteManager.h b/src/CalcViewModel/Common/CopyPasteManager.h deleted file mode 100644 index b393dab5..00000000 --- a/src/CalcViewModel/Common/CopyPasteManager.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "AppResourceProvider.h" -#include "NavCategory.h" - -namespace CalculatorUnitTests -{ - class CopyPasteManagerTest; -} - -namespace CalculatorApp -{ - inline constexpr auto QwordType = 1; - inline constexpr auto DwordType = 2; - inline constexpr auto WordType = 3; - inline constexpr auto ByteType = 4; - inline constexpr auto HexBase = 5; - inline constexpr auto DecBase = 6; - inline constexpr auto OctBase = 7; - inline constexpr auto BinBase = 8; - - class CopyPasteManager - { - public: - static void CopyToClipboard(Platform::String ^ stringToCopy); - static concurrency::task GetStringToPaste( - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1, - int bitLengthType = -1); - static bool HasStringToPaste() - { - return ClipboardTextFormat() >= 0; - } - - static constexpr auto PasteErrorString = L"NoOp"; - - private: - static int ClipboardTextFormat(); - static Platform::String - ^ ValidatePasteExpression(Platform::String ^ pastedText, CalculatorApp::Common::ViewMode mode, int programmerNumberBase, int bitLengthType); - static Platform::String - ^ ValidatePasteExpression( - Platform::String ^ pastedText, - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase, - int bitLengthType); - - static std::vector - ExtractOperands(const std::wstring& pasteExpression, CalculatorApp::Common::ViewMode mode, int programmerNumberBase = -1, int bitLengthType = -1); - static bool ExpressionRegExMatch( - std::vector operands, - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1, - int bitLengthType = -1); - - static std::pair GetMaxOperandLengthAndValue( - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1, - int bitLengthType = -1); - static std::wstring SanitizeOperand(const std::wstring& operand); - static bool TryOperandToULL(const std::wstring& operand, int numberBase, unsigned long long int& result); - static size_t OperandLength( - const std::wstring& operand, - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1); - static size_t StandardScientificOperandLength(const std::wstring& operand); - static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase); - static std::wstring RemoveUnwantedCharsFromWstring(const std::wstring& input); - - static constexpr size_t MaxStandardOperandLength = 16; - static constexpr size_t MaxScientificOperandLength = 32; - static constexpr size_t MaxConverterInputLength = 16; - static constexpr size_t MaxOperandCount = 100; - static constexpr size_t MaxPasteableLength = 512; - static constexpr size_t MaxExponentLength = 4; - static constexpr size_t MaxProgrammerBitLength = 64; - - static Platform::String ^ supportedFormats[]; - - friend class CalculatorUnitTests::CopyPasteManagerTest; - }; -} diff --git a/src/CalcViewModel/Common/DateCalculator.cpp b/src/CalcViewModel/Common/DateCalculator.cpp deleted file mode 100644 index 8d5bedb5..00000000 --- a/src/CalcViewModel/Common/DateCalculator.cpp +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "DateCalculator.h" - -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::Globalization; -using namespace CalculatorApp::Common::DateCalculation; - -DateCalculationEngine::DateCalculationEngine(_In_ String ^ calendarIdentifier) -{ - m_calendar = ref new Calendar(); - m_calendar->ChangeTimeZone("UTC"); - m_calendar->ChangeCalendarSystem(calendarIdentifier); -} - -// Adding Duration to a Date -// Returns: True if function succeeds to calculate the date else returns False -bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime* endDate) -{ - auto currentCalendarSystem = m_calendar->GetCalendarSystem(); - - try - { - m_calendar->SetDateTime(startDate); - - // The Japanese Era system can have multiple year partitions within the same year. - // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1. - // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results - // in a date in Heisei 31. To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date - // math, and then convert back to the Japanese era system. This works because the Japanese era system maintains the same year/month boundaries and - // durations as the Gregorian system and is only different in display value. - if (currentCalendarSystem == CalendarIdentifiers::Japanese) - { - m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian); - } - - if (duration.year != 0) - { - m_calendar->AddYears(duration.year); - } - if (duration.month != 0) - { - m_calendar->AddMonths(duration.month); - } - if (duration.day != 0) - { - m_calendar->AddDays(duration.day); - } - - *endDate = m_calendar->GetDateTime(); - } - catch (Platform::InvalidArgumentException ^ ex) - { - // ensure that we revert to the correct calendar system - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - // Do nothing - return false; - } - - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - return true; -} - -// Subtracting Duration from a Date -// Returns: True if function succeeds to calculate the date else returns False -bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime* endDate) -{ - auto currentCalendarSystem = m_calendar->GetCalendarSystem(); - - // For Subtract the Algorithm is different than Add. Here the smaller units are subtracted first - // and then the larger units. - try - { - m_calendar->SetDateTime(startDate); - - // The Japanese Era system can have multiple year partitions within the same year. - // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1. - // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results - // in a date in Heisei 31. To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date - // math, and then convert back to the Japanese era system. This works because the Japanese era system maintains the same year/month boundaries and - // durations as the Gregorian system and is only different in display value. - if (currentCalendarSystem == CalendarIdentifiers::Japanese) - { - m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian); - } - - if (duration.day != 0) - { - m_calendar->AddDays(-duration.day); - } - if (duration.month != 0) - { - m_calendar->AddMonths(-duration.month); - } - if (duration.year != 0) - { - m_calendar->AddYears(-duration.year); - } - *endDate = m_calendar->GetDateTime(); - } - catch (Platform::InvalidArgumentException ^ ex) - { - // ensure that we revert to the correct calendar system - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - // Do nothing - return false; - } - - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - // Check that the UniversalTime value is not negative - return (endDate->UniversalTime >= 0); -} - -// Calculate the difference between two dates -void DateCalculationEngine::GetDateDifference(_In_ DateTime date1, _In_ DateTime date2, _In_ DateUnit outputFormat, _Out_ DateDifference* difference) -{ - DateTime startDate; - DateTime endDate; - DateTime pivotDate; - DateTime tempPivotDate; - UINT daysDiff = 0; - UINT differenceInDates[c_unitsOfDate] = { 0 }; - - if (date1.UniversalTime < date2.UniversalTime) - { - startDate = date1; - endDate = date2; - } - else - { - startDate = date2; - endDate = date1; - } - - pivotDate = startDate; - - daysDiff = GetDifferenceInDays(startDate, endDate); - - // If output has units other than days - // 0th bit: Year, 1st bit: Month, 2nd bit: Week, 3rd bit: Day - if (static_cast(outputFormat) & 7) - { - UINT daysInMonth; - UINT approximateDaysInYear; - - // If we're unable to calculate the days-in-month or days-in-year, we'll leave the values at 0. - if (TryGetCalendarDaysInMonth(startDate, daysInMonth) && TryGetCalendarDaysInYear(endDate, approximateDaysInYear)) - { - UINT daysIn[c_unitsOfDate] = { approximateDaysInYear, daysInMonth, c_daysInWeek, 1 }; - - for (int unitIndex = 0; unitIndex < c_unitsGreaterThanDays; unitIndex++) - { - tempPivotDate = pivotDate; - - // Check if the bit flag is set for the date unit - DateUnit dateUnit = static_cast(1 << unitIndex); - - if (static_cast(outputFormat & dateUnit)) - { - bool isEndDateHit = false; - differenceInDates[unitIndex] = (daysDiff / daysIn[unitIndex]); - - if (differenceInDates[unitIndex] != 0) - { - try - { - pivotDate = AdjustCalendarDate(pivotDate, dateUnit, static_cast(differenceInDates[unitIndex])); - } - catch (Platform::InvalidArgumentException ^) - { - // Operation failed due to out of bound result - // Do nothing - differenceInDates[unitIndex] = 0; - } - } - - int tempDaysDiff; - - do - { - tempDaysDiff = GetDifferenceInDays(pivotDate, endDate); - - if (tempDaysDiff < 0) - { - // pivotDate has gone over the end date; start from the beginning of this unit - differenceInDates[unitIndex] -= 1; - pivotDate = tempPivotDate; - pivotDate = AdjustCalendarDate(pivotDate, dateUnit, static_cast(differenceInDates[unitIndex])); - isEndDateHit = true; - } - else if (tempDaysDiff > 0) - { - if (isEndDateHit) - { - // This is the closest the pivot can get to the end date for this unit - break; - } - - // pivotDate is still below the end date - try - { - pivotDate = AdjustCalendarDate(pivotDate, dateUnit, 1); - differenceInDates[unitIndex] += 1; - } - catch (Platform::InvalidArgumentException ^) - { - // handling for 31st Dec, 9999 last valid date - // Do nothing - break out - break; - } - } - } while (tempDaysDiff != 0); // dates are the same - exit the loop - - tempPivotDate = AdjustCalendarDate(tempPivotDate, dateUnit, static_cast(differenceInDates[unitIndex])); - pivotDate = tempPivotDate; - daysDiff = GetDifferenceInDays(pivotDate, endDate); - } - } - } - } - - differenceInDates[3] = daysDiff; - - difference->year = differenceInDates[0]; - difference->month = differenceInDates[1]; - difference->week = differenceInDates[2]; - difference->day = differenceInDates[3]; -} - -// Private Methods - -// Gets number of days between the two date time values -int DateCalculationEngine::GetDifferenceInDays(DateTime date1, DateTime date2) -{ - // A tick is defined as the number of 100 nanoseconds - long long ticksDifference = date2.UniversalTime - date1.UniversalTime; - return static_cast(ticksDifference / static_cast(c_day)); -} - -// Gets number of Calendar days in the month in which this date falls. -// Returns true if successful, false otherwise. -bool DateCalculationEngine::TryGetCalendarDaysInMonth(_In_ DateTime date, _Out_ UINT& daysInMonth) -{ - bool result = false; - m_calendar->SetDateTime(date); - - // NumberOfDaysInThisMonth returns -1 if unknown. - int daysInThisMonth = m_calendar->NumberOfDaysInThisMonth; - if (daysInThisMonth != -1) - { - daysInMonth = static_cast(daysInThisMonth); - result = true; - } - - return result; -} - -// Gets number of Calendar days in the year in which this date falls. -// Returns true if successful, false otherwise. -bool DateCalculationEngine::TryGetCalendarDaysInYear(_In_ DateTime date, _Out_ UINT& daysInYear) -{ - bool result = false; - UINT days = 0; - - m_calendar->SetDateTime(date); - - // NumberOfMonthsInThisYear returns -1 if unknown. - int monthsInYear = m_calendar->NumberOfMonthsInThisYear; - if (monthsInYear != -1) - { - bool monthResult = true; - - // Not all years begin with Month 1. - int firstMonthThisYear = m_calendar->FirstMonthInThisYear; - for (int month = 0; month < monthsInYear; month++) - { - m_calendar->Month = firstMonthThisYear + month; - - // NumberOfDaysInThisMonth returns -1 if unknown. - int daysInMonth = m_calendar->NumberOfDaysInThisMonth; - if (daysInMonth == -1) - { - monthResult = false; - break; - } - - days += daysInMonth; - } - - if (monthResult) - { - daysInYear = days; - result = true; - } - } - - return result; -} - -// Adds/Subtracts certain value for a particular date unit -DateTime DateCalculationEngine::AdjustCalendarDate(Windows::Foundation::DateTime date, DateUnit dateUnit, int difference) -{ - m_calendar->SetDateTime(date); - - // The Japanese Era system can have multiple year partitions within the same year. - // For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1. - // The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results in - // a date in Heisei 31. To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date math, - // and then convert back to the Japanese era system. This works because the Japanese era system maintains the same year/month boundaries and durations as - // the Gregorian system and is only different in display value. - auto currentCalendarSystem = m_calendar->GetCalendarSystem(); - if (currentCalendarSystem == CalendarIdentifiers::Japanese) - { - m_calendar->ChangeCalendarSystem(CalendarIdentifiers::Gregorian); - } - - switch (dateUnit) - { - case DateUnit::Year: - m_calendar->AddYears(difference); - break; - case DateUnit::Month: - m_calendar->AddMonths(difference); - break; - case DateUnit::Week: - m_calendar->AddWeeks(difference); - break; - } - - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - return m_calendar->GetDateTime(); -} diff --git a/src/CalcViewModel/Common/DateCalculator.h b/src/CalcViewModel/Common/DateCalculator.h deleted file mode 100644 index e71f02f1..00000000 --- a/src/CalcViewModel/Common/DateCalculator.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -const uint64_t c_millisecond = 10000; -const uint64_t c_second = 1000 * c_millisecond; -const uint64_t c_minute = 60 * c_second; -const uint64_t c_hour = 60 * c_minute; -const uint64_t c_day = 24 * c_hour; - -const int c_unitsOfDate = 4; // Units Year,Month,Week,Day -const int c_unitsGreaterThanDays = 3; // Units Greater than Days (Year/Month/Week) 3 -const int c_daysInWeek = 7; - -namespace CalculatorApp -{ - namespace Common - { - namespace DateCalculation - { - public - enum class _Enum_is_bitflag_ DateUnit - { - Year = 0x01, - Month = 0x02, - Week = 0x04, - Day = 0x08 - }; - - // Struct to store the difference between two Dates in the form of Years, Months , Weeks - struct DateDifference - { - int year = 0; - int month = 0; - int week = 0; - int day = 0; - }; - - class DateCalculationEngine - { - public: - // Constructor - DateCalculationEngine(_In_ Platform::String ^ calendarIdentifier); - - // Public Methods - bool __nothrow - AddDuration(_In_ Windows::Foundation::DateTime startDate, _In_ const DateDifference& duration, _Out_ Windows::Foundation::DateTime* endDate); - bool __nothrow SubtractDuration( - _In_ Windows::Foundation::DateTime startDate, - _In_ const DateDifference& duration, - _Out_ Windows::Foundation::DateTime* endDate); - void __nothrow GetDateDifference( - _In_ Windows::Foundation::DateTime date1, - _In_ Windows::Foundation::DateTime date2, - _In_ DateUnit outputFormat, - _Out_ DateDifference* difference); - - private: - // Private Variables - Windows::Globalization::Calendar ^ m_calendar; - - // Private Methods - int GetDifferenceInDays(Windows::Foundation::DateTime date1, Windows::Foundation::DateTime date2); - bool TryGetCalendarDaysInMonth(_In_ Windows::Foundation::DateTime date, _Out_ UINT& daysInMonth); - bool TryGetCalendarDaysInYear(_In_ Windows::Foundation::DateTime date, _Out_ UINT& daysInYear); - Windows::Foundation::DateTime AdjustCalendarDate(Windows::Foundation::DateTime date, DateUnit dateUnit, int difference); - }; - } - } -} diff --git a/src/CalcViewModel/Common/DelegateCommand.h b/src/CalcViewModel/Common/DelegateCommand.h deleted file mode 100644 index 3a341287..00000000 --- a/src/CalcViewModel/Common/DelegateCommand.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace Common - { - template - ref class DelegateCommand : public Windows::UI::Xaml::Input::ICommand - { - internal : - - typedef void (TTarget::*CommandHandlerFunc)(Platform::Object ^); - - DelegateCommand(TTarget ^ target, CommandHandlerFunc func) - : m_weakTarget(target) - , m_function(func) - { - } - - private: - // Explicit, and private, implementation of ICommand, this way of programming makes it so - // the ICommand methods will only be available if the ICommand interface is requested via a dynamic_cast - // The ICommand interface is meant to be consumed by Xaml and not by the app, this is a defensive measure against - // code in the app calling Execute. - virtual void ExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::Execute - { - TTarget ^ target = m_weakTarget.Resolve(); - if (target) - { - (target->*m_function)(parameter); - } - } - - virtual bool CanExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::CanExecute - { - return true; - } - - virtual event Windows::Foundation::EventHandler^ CanExecuteChangedImpl - { - virtual Windows::Foundation::EventRegistrationToken add(Windows::Foundation::EventHandler^ handler) sealed = Windows::UI::Xaml::Input::ICommand::CanExecuteChanged::add - { - return m_canExecuteChanged += handler; - } - virtual void remove(Windows::Foundation::EventRegistrationToken token) sealed = Windows::UI::Xaml::Input::ICommand::CanExecuteChanged::remove - { - m_canExecuteChanged -= token; - } - } - - private: - - event Windows::Foundation::EventHandler^ m_canExecuteChanged; - - CommandHandlerFunc m_function; - Platform::WeakReference m_weakTarget; - }; - - template - DelegateCommand ^ MakeDelegate(TTarget ^ target, TFuncPtr&& function) { - return ref new DelegateCommand(target, std::forward(function)); - } - - } -} diff --git a/src/CalcViewModel/Common/DisplayExpressionToken.h b/src/CalcViewModel/Common/DisplayExpressionToken.h deleted file mode 100644 index aaaaf37c..00000000 --- a/src/CalcViewModel/Common/DisplayExpressionToken.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "Utils.h" - -namespace CalculatorApp::Common -{ -public - enum class TokenType - { - Operator, - Operand, - Separator - }; - - [Windows::UI::Xaml::Data::Bindable] public ref class DisplayExpressionToken sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - internal : DisplayExpressionToken(Platform::String ^ token, int tokenPosition, bool fEditable, TokenType type) - : m_Token(token) - , m_TokenPosition(tokenPosition) - , m_IsTokenEditable(fEditable) - , m_Type(type) - , m_OriginalToken(token) - , m_InEditMode(false) - { - } - - public: - OBSERVABLE_OBJECT(); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Token); - OBSERVABLE_PROPERTY_RW(int, TokenPosition); - OBSERVABLE_PROPERTY_RW(bool, IsTokenEditable); - OBSERVABLE_PROPERTY_RW(int, CommandIndex); - OBSERVABLE_PROPERTY_R(Platform::String ^, OriginalToken); - - property bool IsTokenInEditMode - { - bool get() - { - return m_InEditMode; - } - void set(bool val) - { - if (!val) - { - m_OriginalToken = ref new Platform::String(m_Token->Data()); - } - m_InEditMode = val; - } - } - internal : OBSERVABLE_PROPERTY_RW(TokenType, Type); - - private: - bool m_InEditMode; - }; -} diff --git a/src/CalcViewModel/Common/EngineResourceProvider.cpp b/src/CalcViewModel/Common/EngineResourceProvider.cpp deleted file mode 100644 index b65a2a31..00000000 --- a/src/CalcViewModel/Common/EngineResourceProvider.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "EngineResourceProvider.h" -#include "Common/LocalizationSettings.h" - -using namespace CalculatorApp::Common; -using namespace Platform; -using namespace Windows::ApplicationModel::Resources; -using namespace std; - -namespace CalculatorApp -{ - EngineResourceProvider::EngineResourceProvider() - { - m_resLoader = ResourceLoader::GetForViewIndependentUse("CEngineStrings"); - } - - wstring EngineResourceProvider::GetCEngineString(const wstring& id) - { - const auto& localizationSettings = LocalizationSettings::GetInstance(); - - if (id.compare(L"sDecimal") == 0) - { - return localizationSettings.GetDecimalSeparatorStr(); - } - - if (id.compare(L"sThousand") == 0) - { - return localizationSettings.GetNumberGroupingSeparatorStr(); - } - - if (id.compare(L"sGrouping") == 0) - { - // The following groupings are the onces that CalcEngine supports. - // 0;0 0x000 - no grouping - // 3;0 0x003 - group every 3 digits - // 3;2;0 0x023 - group 1st 3 and then every 2 digits - // 4;0 0x004 - group every 4 digits - // 5;3;2;0 0x235 - group 5, then 3, then every 2 - wstring numberGroupingString = localizationSettings.GetNumberGroupingStr(); - return numberGroupingString; - } - - StringReference idRef(id.c_str()); - String ^ str = m_resLoader->GetString(idRef); - return str->Begin(); - } -} diff --git a/src/CalcViewModel/Common/EngineResourceProvider.h b/src/CalcViewModel/Common/EngineResourceProvider.h deleted file mode 100644 index 8b5bb479..00000000 --- a/src/CalcViewModel/Common/EngineResourceProvider.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/CalculatorResource.h" - -namespace CalculatorApp -{ - class EngineResourceProvider : public CalculationManager::IResourceProvider - { - public: - EngineResourceProvider(); - virtual std::wstring GetCEngineString(const std::wstring& id) override; - - private: - Windows::ApplicationModel::Resources::ResourceLoader ^ m_resLoader; - }; -} diff --git a/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp b/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp deleted file mode 100644 index e927b262..00000000 --- a/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "ExpressionCommandDeserializer.h" - -using namespace CalculatorApp::Common; -using namespace Windows::Storage::Streams; - -CommandDeserializer::CommandDeserializer(_In_ DataReader ^ dataReader) - : m_dataReader(dataReader) -{ -} - -std::shared_ptr CommandDeserializer::Deserialize(_In_ CalculationManager::CommandType cmdType) -{ - switch (cmdType) - { - case CalculationManager::CommandType::OperandCommand: - - return std::make_shared(DeserializeOperand()); - break; - - case CalculationManager::CommandType::Parentheses: - - return std::make_shared(DeserializeParentheses()); - break; - - case CalculationManager::CommandType::UnaryCommand: - - return std::make_shared(DeserializeUnary()); - break; - - case CalculationManager::CommandType::BinaryCommand: - - return std::make_shared(DeserializeBinary()); - break; - - default: - throw ref new Platform::Exception(E_INVALIDARG, ref new Platform::String(L"Unknown command type")); - } -} - -COpndCommand CommandDeserializer::DeserializeOperand() -{ - bool fNegative = m_dataReader->ReadBoolean(); - bool fDecimal = m_dataReader->ReadBoolean(); - bool fSciFmt = m_dataReader->ReadBoolean(); - - std::shared_ptr> cmdVector = std::make_shared>(); - auto cmdVectorSize = m_dataReader->ReadUInt32(); - - for (unsigned int j = 0; j < cmdVectorSize; ++j) - { - int eachOpndcmd = m_dataReader->ReadInt32(); - cmdVector->Append(eachOpndcmd); - } - - return COpndCommand(cmdVector, fNegative, fDecimal, fSciFmt); -} - -CParentheses CommandDeserializer::DeserializeParentheses() -{ - int parenthesisCmd = m_dataReader->ReadInt32(); - return CParentheses(parenthesisCmd); -} - -CUnaryCommand CommandDeserializer::DeserializeUnary() -{ - auto cmdSize = m_dataReader->ReadUInt32(); - std::shared_ptr> cmdVector = std::make_shared>(); - - if (cmdSize == 1) - { - int eachOpndcmd = m_dataReader->ReadInt32(); - return CUnaryCommand(eachOpndcmd); - } - else - { - int eachOpndcmd1 = m_dataReader->ReadInt32(); - int eachOpndcmd2 = m_dataReader->ReadInt32(); - return CUnaryCommand(eachOpndcmd1, eachOpndcmd2); - } -} - -CBinaryCommand CommandDeserializer::DeserializeBinary() -{ - int cmd = m_dataReader->ReadInt32(); - return CBinaryCommand(cmd); -} diff --git a/src/CalcViewModel/Common/ExpressionCommandDeserializer.h b/src/CalcViewModel/Common/ExpressionCommandDeserializer.h deleted file mode 100644 index 833b6bf6..00000000 --- a/src/CalcViewModel/Common/ExpressionCommandDeserializer.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/ExpressionCommand.h" - -namespace CalculatorApp -{ - namespace Common - { - class CommandDeserializer - { - public: - CommandDeserializer(_In_ Windows::Storage::Streams::DataReader ^ dataReader); - std::shared_ptr Deserialize(_In_ CalculationManager::CommandType cmdType); - - private: - Windows::Storage::Streams::DataReader ^ m_dataReader; - COpndCommand DeserializeOperand(); - CParentheses DeserializeParentheses(); - CUnaryCommand DeserializeUnary(); - CBinaryCommand DeserializeBinary(); - }; - } -} diff --git a/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp b/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp deleted file mode 100644 index bbf9e183..00000000 --- a/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "Common/ExpressionCommandSerializer.h" - -using namespace CalculatorApp::Common; -using namespace Windows::Storage::Streams; - -SerializeCommandVisitor::SerializeCommandVisitor(_In_ DataWriter ^ dataWriter) - : m_dataWriter(dataWriter) -{ -} - -void SerializeCommandVisitor::Visit(_In_ COpndCommand& opndCmd) -{ - m_dataWriter->WriteBoolean(opndCmd.IsNegative()); - m_dataWriter->WriteBoolean(opndCmd.IsDecimalPresent()); - m_dataWriter->WriteBoolean(opndCmd.IsSciFmt()); - - auto opndCmds = opndCmd.GetCommands(); - unsigned int opndCmdSize; - opndCmds->GetSize(&opndCmdSize); - m_dataWriter->WriteUInt32(opndCmdSize); - for (unsigned int j = 0; j < opndCmdSize; ++j) - { - int eachOpndcmd; - opndCmds->GetAt(j, &eachOpndcmd); - m_dataWriter->WriteInt32(eachOpndcmd); - } -} - -void SerializeCommandVisitor::Visit(_In_ CUnaryCommand& unaryCmd) -{ - auto cmds = unaryCmd.GetCommands(); - unsigned int cmdSize; - cmds->GetSize(&cmdSize); - m_dataWriter->WriteUInt32(cmdSize); - for (unsigned int j = 0; j < cmdSize; ++j) - { - int eachOpndcmd; - cmds->GetAt(j, &eachOpndcmd); - m_dataWriter->WriteInt32(eachOpndcmd); - } -} - -void SerializeCommandVisitor::Visit(_In_ CBinaryCommand& binaryCmd) -{ - int cmd = binaryCmd.GetCommand(); - m_dataWriter->WriteInt32(cmd); -} - -void SerializeCommandVisitor::Visit(_In_ CParentheses& paraCmd) -{ - int parenthesisCmd = paraCmd.GetCommand(); - m_dataWriter->WriteInt32(parenthesisCmd); -} diff --git a/src/CalcViewModel/Common/ExpressionCommandSerializer.h b/src/CalcViewModel/Common/ExpressionCommandSerializer.h deleted file mode 100644 index 23303fe7..00000000 --- a/src/CalcViewModel/Common/ExpressionCommandSerializer.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/ExpressionCommand.h" - -namespace CalculatorApp -{ - namespace Common - { - class SerializeCommandVisitor : public ISerializeCommandVisitor - { - public: - SerializeCommandVisitor(_In_ Windows::Storage::Streams::DataWriter ^ dataWriter); - - void Visit(_In_ COpndCommand& opndCmd); - void Visit(_In_ CUnaryCommand& unaryCmd); - void Visit(_In_ CBinaryCommand& binaryCmd); - void Visit(_In_ CParentheses& paraCmd); - - private: - Windows::Storage::Streams::DataWriter ^ m_dataWriter; - }; - } -} diff --git a/src/CalcViewModel/Common/KeyboardShortcutManager.cpp b/src/CalcViewModel/Common/KeyboardShortcutManager.cpp deleted file mode 100644 index 7d9cfffa..00000000 --- a/src/CalcViewModel/Common/KeyboardShortcutManager.cpp +++ /dev/null @@ -1,849 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "KeyboardShortcutManager.h" -#include "AppResourceProvider.h" -#include "ApplicationViewModel.h" -#include "LocalizationSettings.h" - -using namespace Concurrency; -using namespace Platform; -using namespace std; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::UI::Core; -using namespace Windows::UI::Xaml::Controls::Primitives; -using namespace Windows::System; -using namespace Utils; -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::ViewModel; - -namespace MUXC = Microsoft::UI::Xaml::Controls; - -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, Character); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKey); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyShiftChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyAltChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlShiftChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyInverseChord); -DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlInverseChord); - -static multimap> s_CharacterForButtons; -static multimap> s_VirtualKeysForButtons; -static multimap> s_VirtualKeyControlChordsForButtons; -static multimap> s_VirtualKeyShiftChordsForButtons; -static multimap> s_VirtualKeyAltChordsForButtons; -static multimap> s_VirtualKeyControlShiftChordsForButtons; -static multimap> s_VirtualKeyInverseChordsForButtons; -static multimap> s_VirtualKeyControlInverseChordsForButtons; - -static multimap s_ShiftKeyPressed; -static multimap s_ControlKeyPressed; -static multimap s_ShiftButtonChecked; -static multimap s_IsDropDownOpen; - -static reader_writer_lock s_keyboardShortcutMapLock; - -namespace CalculatorApp -{ - namespace Common - { - // Lights up all of the buttons in the given range - // The range is defined by a pair of iterators - template - void LightUpButtons(const T& buttons) - { - auto iterator = buttons.first; - for (; iterator != buttons.second; ++iterator) - { - auto button = iterator->second.Resolve(); - if (button && button->IsEnabled) - { - LightUpButton(button); - } - } - } - - void LightUpButton(ButtonBase ^ button) - { - // If the button is a toggle button then we don't need - // to change the UI of the button - if (dynamic_cast(button)) - { - return; - } - - // 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; - - 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); - } - - // Cancel the timer after we're done so it only fires once - auto timer = timerWeakReference.Resolve(); - if (timer) - { - timer->Stop(); - } - }); - timer->Start(); - } - - // Looks for the first button reference that it can resolve - // and execute its command. - // NOTE: It is assumed that all buttons associated with a particular - // key have the same command - template - void RunFirstEnabledButtonCommand(const T& buttons) - { - auto buttonIterator = buttons.first; - for (; buttonIterator != buttons.second; ++buttonIterator) - { - auto button = buttonIterator->second.Resolve(); - if (button && button->IsEnabled) - { - RunButtonCommand(button); - break; - } - } - } - - void RunButtonCommand(ButtonBase ^ button) - { - if (button->IsEnabled) - { - auto command = button->Command; - auto parameter = button->CommandParameter; - if (command && command->CanExecute(parameter)) - { - command->Execute(parameter); - } - - auto radio = dynamic_cast(button); - if (radio) - { - radio->IsChecked = true; - return; - } - - auto toggle = dynamic_cast(button); - if (toggle) - { - toggle->IsChecked = !toggle->IsChecked->Value; - return; - } - } - } - } -} - -static multimap s_ignoreNextEscape; -static multimap s_keepIgnoringEscape; -static multimap s_fHonorShortcuts; -static multimap s_fHandledEnter; -static multimap s_AboutFlyout; - -void KeyboardShortcutManager::IgnoreEscape(bool onlyOnce) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - int viewId = Utils::GetWindowId(); - - if (s_ignoreNextEscape.find(viewId) != s_ignoreNextEscape.end()) - { - s_ignoreNextEscape.erase(viewId); - s_ignoreNextEscape.insert(std::make_pair(viewId, true)); - } - - if (s_keepIgnoringEscape.find(viewId) != s_keepIgnoringEscape.end()) - { - s_keepIgnoringEscape.erase(viewId); - s_keepIgnoringEscape.insert(std::make_pair(viewId, !onlyOnce)); - } -} - -void KeyboardShortcutManager::HonorEscape() -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - int viewId = Utils::GetWindowId(); - - if (s_ignoreNextEscape.find(viewId) != s_ignoreNextEscape.end()) - { - s_ignoreNextEscape.erase(viewId); - s_ignoreNextEscape.insert(std::make_pair(viewId, false)); - } - - if (s_keepIgnoringEscape.find(viewId) != s_keepIgnoringEscape.end()) - { - s_keepIgnoringEscape.erase(viewId); - s_keepIgnoringEscape.insert(std::make_pair(viewId, false)); - } -} - -void KeyboardShortcutManager::OnCharacterPropertyChanged(DependencyObject ^ target, String ^ oldValue, String ^ newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_CharacterForButtons.find(viewId); - - if (iterViewMap != s_CharacterForButtons.end()) - { - if (oldValue) - { - iterViewMap->second.erase(oldValue->Data()[0]); - } - - if (newValue) - { - if (newValue == L".") - { - wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator(); - iterViewMap->second.insert(std::make_pair(decSep, WeakReference(button))); - } - else - { - iterViewMap->second.insert(std::make_pair(newValue->Data()[0], WeakReference(button))); - } - } - } - else - { - s_CharacterForButtons.insert(std::make_pair(viewId, std::multimap())); - - if (newValue == L".") - { - wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator(); - s_CharacterForButtons.find(viewId)->second.insert(std::make_pair(decSep, WeakReference(button))); - } - else - { - s_CharacterForButtons.find(viewId)->second.insert(std::make_pair(newValue->Data()[0], WeakReference(button))); - } - } -} - -void KeyboardShortcutManager::OnVirtualKeyPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = static_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeysForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeysForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeysForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeysForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyControlChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - Control ^ control = dynamic_cast(target); - - if (control == nullptr) - { - // Handling Ctrl+E shortcut for Date Calc, target would be NavigationView^ in that case - control = safe_cast(target); - } - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyControlChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyControlChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(control))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyControlChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyControlChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(control))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyShiftChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyShiftChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyShiftChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyShiftChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyAltChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - MUXC::NavigationView ^ navView = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyAltChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyAltChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(navView))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyAltChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyAltChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(navView))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyControlShiftChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyControlShiftChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyControlShiftChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyInverseChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyInverseChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyInverseChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyInverseChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -void KeyboardShortcutManager::OnVirtualKeyControlInverseChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto button = safe_cast(target); - - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId); - - // Check if the View Id has already been registered - if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end()) - { - iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button))); - } - else - { - // If the View Id is not already registered, then register it and make the entry - s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(viewId, std::multimap())); - s_VirtualKeyControlInverseChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button))); - } -} - -// In the three event handlers below we will not mark the event as handled -// because this is a supplemental operation and we don't want to interfere with -// the normal keyboard handling. -void KeyboardShortcutManager::OnCharacterReceivedHandler(CoreWindow ^ sender, CharacterReceivedEventArgs ^ args) -{ - int viewId = Utils::GetWindowId(); - auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId); - - if (currentHonorShortcuts != s_fHonorShortcuts.end()) - { - if (currentHonorShortcuts->second) - { - wchar_t character = static_cast(args->KeyCode); - auto buttons = s_CharacterForButtons.find(viewId)->second.equal_range(character); - - RunFirstEnabledButtonCommand(buttons); - - LightUpButtons(buttons); - } - } -} - -const std::multimap& GetCurrentKeyDictionary(MyVirtualKey key, bool altPressed = false) -{ - int viewId = Utils::GetWindowId(); - - if (altPressed) - { - return s_VirtualKeyAltChordsForButtons.find(viewId)->second; - } - else if ( - (s_ShiftKeyPressed.find(viewId)->second) - && ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down)) - { - return s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second; - } - else if (s_ShiftKeyPressed.find(viewId)->second) - { - return s_VirtualKeyShiftChordsForButtons.find(viewId)->second; - } - else if (s_ShiftButtonChecked.find(viewId)->second) - { - if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down) - { - auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId); - if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end()) - { - for (auto iterator = iterViewMap->second.begin(); iterator != iterViewMap->second.end(); ++iterator) - { - if (key == iterator->first) - { - return s_VirtualKeyControlInverseChordsForButtons.find(viewId)->second; - } - } - } - } - else - { - auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId); - if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end()) - { - for (auto iterator = iterViewMap->second.begin(); iterator != iterViewMap->second.end(); ++iterator) - { - if (key == iterator->first) - { - return s_VirtualKeyInverseChordsForButtons.find(viewId)->second; - } - } - } - } - } - if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down) - { - return s_VirtualKeyControlChordsForButtons.find(viewId)->second; - } - else - { - return s_VirtualKeysForButtons.find(viewId)->second; - } -} - -void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow ^ sender, KeyEventArgs ^ args) -{ - // If keyboard shortcuts like Ctrl+C or Ctrl+V are not handled - if (!args->Handled) - { - auto key = args->VirtualKey; - int viewId = Utils::GetWindowId(); - - auto currentControlKeyPressed = s_ControlKeyPressed.find(viewId); - auto currentShiftKeyPressed = s_ShiftKeyPressed.find(viewId); - - bool isControlKeyPressed = (currentControlKeyPressed != s_ControlKeyPressed.end()) && (currentControlKeyPressed->second); - bool isShiftKeyPressed = (currentShiftKeyPressed != s_ShiftKeyPressed.end()) && (currentShiftKeyPressed->second); - - // Handle Ctrl + E for DateCalculator - if ((key == VirtualKey::E) && isControlKeyPressed && !isShiftKeyPressed) - { - const auto& lookupMap = GetCurrentKeyDictionary(static_cast(key)); - auto buttons = lookupMap.equal_range(static_cast(key)); - auto navView = buttons.first->second.Resolve(); - auto appViewModel = safe_cast(navView->DataContext); - appViewModel->Mode = ViewMode::Date; - auto categoryName = AppResourceProvider::GetInstance().GetResourceString(L"DateCalculationModeText"); - appViewModel->CategoryName = categoryName; - - auto menuItems = static_cast ^>(navView->MenuItemsSource); - auto flatIndex = NavCategory::GetFlatIndex(ViewMode::Date); - navView->SelectedItem = menuItems->GetAt(flatIndex); - return; - } - - auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId); - - auto currentIgnoreNextEscape = s_ignoreNextEscape.find(viewId); - - if (currentIgnoreNextEscape != s_ignoreNextEscape.end()) - { - if (currentIgnoreNextEscape->second && key == VirtualKey::Escape) - { - auto currentKeepIgnoringEscape = s_keepIgnoringEscape.find(viewId); - - if (currentKeepIgnoringEscape != s_keepIgnoringEscape.end()) - { - if (!currentKeepIgnoringEscape->second) - { - HonorEscape(); - } - return; - } - } - } - - if (key == VirtualKey::Control) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currControlKeyPressed = s_ControlKeyPressed.find(viewId); - - if (currControlKeyPressed != s_ControlKeyPressed.end()) - { - s_ControlKeyPressed.erase(viewId); - s_ControlKeyPressed.insert(std::make_pair(viewId, true)); - } - return; - } - else if (key == VirtualKey::Shift) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currShiftKeyPressed = s_ShiftKeyPressed.find(viewId); - - if (currShiftKeyPressed != s_ShiftKeyPressed.end()) - { - s_ShiftKeyPressed.erase(viewId); - s_ShiftKeyPressed.insert(std::make_pair(viewId, true)); - } - return; - } - - const auto& lookupMap = GetCurrentKeyDictionary(static_cast(key)); - auto buttons = lookupMap.equal_range(static_cast(key)); - - auto currentIsDropDownOpen = s_IsDropDownOpen.find(viewId); - - if (currentHonorShortcuts != s_fHonorShortcuts.end()) - { - 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 - if (currentIsDropDownOpen != s_IsDropDownOpen.end() && !currentIsDropDownOpen->second) - { - // Do not Light Up Buttons when Ctrl+C, Ctrl+V, Ctrl+Insert or Shift+Insert is pressed - if (!(isControlKeyPressed && (key == VirtualKey::C || key == VirtualKey::V || key == VirtualKey::Insert)) - && !(isShiftKeyPressed && (key == VirtualKey::Insert))) - { - LightUpButtons(buttons); - } - } - } - } - } -} - -void KeyboardShortcutManager::OnKeyUpHandler(CoreWindow ^ sender, KeyEventArgs ^ args) -{ - int viewId = Utils::GetWindowId(); - auto key = args->VirtualKey; - - if (key == VirtualKey::Shift) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currentShiftKeyPressed = s_ShiftKeyPressed.find(viewId); - - if (currentShiftKeyPressed != s_ShiftKeyPressed.end()) - { - s_ShiftKeyPressed.erase(viewId); - s_ShiftKeyPressed.insert(std::make_pair(viewId, false)); - } - } - else if (key == VirtualKey::Control) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - auto currControlKeyPressed = s_ControlKeyPressed.find(viewId); - - if (currControlKeyPressed != s_ControlKeyPressed.end()) - { - s_ControlKeyPressed.erase(viewId); - s_ControlKeyPressed.insert(std::make_pair(viewId, false)); - } - } -} - -void KeyboardShortcutManager::OnAcceleratorKeyActivated(CoreDispatcher ^, AcceleratorKeyEventArgs ^ args) -{ - if (args->KeyStatus.IsKeyReleased) - { - auto key = args->VirtualKey; - bool altPressed = args->KeyStatus.IsMenuKeyDown; - - // If the Alt/Menu key is not pressed then we don't care about the key anymore - if (!altPressed) - { - return; - } - - const auto& lookupMap = GetCurrentKeyDictionary(static_cast(key), altPressed); - auto listItems = lookupMap.equal_range(static_cast(key)); - for (auto listIterator = listItems.first; listIterator != listItems.second; ++listIterator) - { - auto item = listIterator->second.Resolve(); - if (item != nullptr) - { - auto navView = safe_cast(item); - - auto menuItems = static_cast ^>(navView->MenuItemsSource); - if (menuItems != nullptr) - { - auto vm = safe_cast(navView->DataContext); - if (nullptr != vm) - { - ViewMode toMode = NavCategory::GetViewModeForVirtualKey(static_cast(key)); - if (NavCategory::IsValidViewMode(toMode)) - { - vm->Mode = toMode; - navView->SelectedItem = menuItems->GetAt(NavCategory::GetFlatIndex(toMode)); - } - } - } - break; - } - } - } - - if (args->VirtualKey == VirtualKey::Escape) - { - int viewId = Utils::GetWindowId(); - auto iterViewMap = s_AboutFlyout.find(viewId); - - if ((iterViewMap != s_AboutFlyout.end()) && (iterViewMap->second != nullptr)) - { - iterViewMap->second->Hide(); - } - } -} - -void KeyboardShortcutManager::Initialize() -{ - auto coreWindow = Window::Current->CoreWindow; - coreWindow->CharacterReceived += - ref new TypedEventHandler(&KeyboardShortcutManager::OnCharacterReceivedHandler); - coreWindow->KeyDown += ref new TypedEventHandler(&KeyboardShortcutManager::OnKeyDownHandler); - coreWindow->KeyUp += ref new TypedEventHandler(&KeyboardShortcutManager::OnKeyUpHandler); - coreWindow->Dispatcher->AcceleratorKeyActivated += - ref new TypedEventHandler(&KeyboardShortcutManager::OnAcceleratorKeyActivated); - - KeyboardShortcutManager::RegisterNewAppViewId(); -} - -void KeyboardShortcutManager::ShiftButtonChecked(bool checked) -{ - int viewId = Utils::GetWindowId(); - - if (s_ShiftButtonChecked.find(viewId) != s_ShiftButtonChecked.end()) - { - s_ShiftButtonChecked.erase(viewId); - s_ShiftButtonChecked.insert(std::make_pair(viewId, checked)); - } -} - -void KeyboardShortcutManager::UpdateDropDownState(bool isOpen) -{ - int viewId = Utils::GetWindowId(); - - if (s_IsDropDownOpen.find(viewId) != s_IsDropDownOpen.end()) - { - s_IsDropDownOpen.erase(viewId); - s_IsDropDownOpen.insert(std::make_pair(viewId, isOpen)); - } -} - -void KeyboardShortcutManager::UpdateDropDownState(Flyout ^ aboutPageFlyout) -{ - int viewId = Utils::GetWindowId(); - - if (s_AboutFlyout.find(viewId) != s_AboutFlyout.end()) - { - s_AboutFlyout.erase(viewId); - s_AboutFlyout.insert(std::make_pair(viewId, aboutPageFlyout)); - } -} - -void KeyboardShortcutManager::HonorShortcuts(bool allow) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - int viewId = Utils::GetWindowId(); - - if (s_fHonorShortcuts.find(viewId) != s_fHonorShortcuts.end()) - { - s_fHonorShortcuts.erase(viewId); - s_fHonorShortcuts.insert(std::make_pair(viewId, allow)); - } -} - -void KeyboardShortcutManager::HandledEnter(bool ishandled) -{ - int viewId = Utils::GetWindowId(); - - if (s_fHandledEnter.find(viewId) != s_fHandledEnter.end()) - { - s_fHandledEnter.erase(viewId); - s_fHandledEnter.insert(std::make_pair(viewId, ishandled)); - } -} - -void KeyboardShortcutManager::RegisterNewAppViewId() -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - int appViewId = Utils::GetWindowId(); - - // Check if the View Id has already been registered - if (s_CharacterForButtons.find(appViewId) == s_CharacterForButtons.end()) - { - s_CharacterForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeysForButtons.find(appViewId) == s_VirtualKeysForButtons.end()) - { - s_VirtualKeysForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyControlChordsForButtons.find(appViewId) == s_VirtualKeyControlChordsForButtons.end()) - { - s_VirtualKeyControlChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyShiftChordsForButtons.find(appViewId) == s_VirtualKeyShiftChordsForButtons.end()) - { - s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyAltChordsForButtons.find(appViewId) == s_VirtualKeyAltChordsForButtons.end()) - { - s_VirtualKeyAltChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end()) - { - s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyInverseChordsForButtons.find(appViewId) == s_VirtualKeyInverseChordsForButtons.end()) - { - s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - if (s_VirtualKeyControlInverseChordsForButtons.find(appViewId) == s_VirtualKeyControlInverseChordsForButtons.end()) - { - s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap())); - } - - s_ShiftKeyPressed.insert(std::make_pair(appViewId, false)); - s_ControlKeyPressed.insert(std::make_pair(appViewId, false)); - s_ShiftButtonChecked.insert(std::make_pair(appViewId, false)); - s_IsDropDownOpen.insert(std::make_pair(appViewId, false)); - s_ignoreNextEscape.insert(std::make_pair(appViewId, false)); - s_keepIgnoringEscape.insert(std::make_pair(appViewId, false)); - s_fHonorShortcuts.insert(std::make_pair(appViewId, true)); - s_fHandledEnter.insert(std::make_pair(appViewId, true)); - s_AboutFlyout.insert(std::make_pair(appViewId, nullptr)); -} - -void KeyboardShortcutManager::OnWindowClosed(int viewId) -{ - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); - - s_CharacterForButtons.erase(viewId); - - s_VirtualKeysForButtons.erase(viewId); - s_VirtualKeyControlChordsForButtons.erase(viewId); - s_VirtualKeyShiftChordsForButtons.erase(viewId); - s_VirtualKeyAltChordsForButtons.erase(viewId); - s_VirtualKeyControlShiftChordsForButtons.erase(viewId); - s_VirtualKeyInverseChordsForButtons.erase(viewId); - s_VirtualKeyControlInverseChordsForButtons.erase(viewId); - - s_ShiftKeyPressed.erase(viewId); - s_ControlKeyPressed.erase(viewId); - s_ShiftButtonChecked.erase(viewId); - s_IsDropDownOpen.erase(viewId); - s_ignoreNextEscape.erase(viewId); - s_keepIgnoringEscape.erase(viewId); - s_fHonorShortcuts.erase(viewId); - s_fHandledEnter.erase(viewId); - s_AboutFlyout.erase(viewId); -} diff --git a/src/CalcViewModel/Common/KeyboardShortcutManager.h b/src/CalcViewModel/Common/KeyboardShortcutManager.h deleted file mode 100644 index 6663f2ce..00000000 --- a/src/CalcViewModel/Common/KeyboardShortcutManager.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "Utils.h" -#include "MyVirtualKey.h" - -namespace CalculatorApp -{ - namespace Common - { - public - ref class KeyboardShortcutManager sealed - { - public: - KeyboardShortcutManager() - { - } - - DEPENDENCY_PROPERTY_OWNER(KeyboardShortcutManager); - - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(Platform::String ^, Character); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKey); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyShiftChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyAltChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlShiftChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyInverseChord); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlInverseChord); - - internal : - - static void - Initialize(); - - // Sometimes, like with popups, escape is treated as special and even - // though it is handled we get it passed through to us. In those cases - // we need to be able to ignore it (looking at e->Handled isn't sufficient - // because that always returns true). - // The onlyOnce flag is used to indicate whether we should only ignore the - // next escape, or keep ignoring until you explicitly HonorEscape. - static void IgnoreEscape(bool onlyOnce); - static void HonorEscape(); - static void HonorShortcuts(bool allow); - static void HandledEnter(bool ishandled); - static void UpdateDropDownState(bool); - static void ShiftButtonChecked(bool checked); - static void UpdateDropDownState(Windows::UI::Xaml::Controls::Flyout ^ aboutPageFlyout); - - static void RegisterNewAppViewId(); - static void OnWindowClosed(int viewId); - - private: - static void OnCharacterPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, Platform::String ^ oldValue, Platform::String ^ newValue); - - static void OnVirtualKeyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void OnVirtualKeyControlChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void OnVirtualKeyShiftChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void OnVirtualKeyInverseChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void - OnVirtualKeyControlInverseChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void OnVirtualKeyAltChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void - OnVirtualKeyControlShiftChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue); - - static void OnCharacterReceivedHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::CharacterReceivedEventArgs ^ args); - static void OnKeyDownHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args); - static void OnKeyUpHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args); - static void OnAcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher ^, Windows::UI::Core::AcceleratorKeyEventArgs ^ args); - }; - } -} diff --git a/src/CalcViewModel/Common/LocalizationService.cpp b/src/CalcViewModel/Common/LocalizationService.cpp deleted file mode 100644 index 848360ee..00000000 --- a/src/CalcViewModel/Common/LocalizationService.cpp +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "LocalizationService.h" -#include "LocalizationSettings.h" -#include "AppResourceProvider.h" - -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::LocalizationServiceProperties; -using namespace Concurrency; -using namespace Platform; -using namespace Platform::Collections; -using namespace std; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::ApplicationModel::Resources::Core; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::Globalization; -using namespace Windows::Globalization::DateTimeFormatting; -using namespace Windows::Globalization::Fonts; -using namespace Windows::Globalization::NumberFormatting; -using namespace Windows::System::UserProfile; -using namespace Windows::UI::Text; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Controls::Primitives; -using namespace Windows::UI::Xaml::Documents; -using namespace Windows::UI::Xaml::Media; - -DEPENDENCY_PROPERTY_INITIALIZATION(LocalizationService, FontType); -DEPENDENCY_PROPERTY_INITIALIZATION(LocalizationService, FontSize); - -static reader_writer_lock s_locServiceInstanceLock; - -LocalizationService ^ LocalizationService::s_singletonInstance = nullptr; - -// Resources for the engine use numbers as keys. It's inconvenient, but also difficult to -// change given that the engine heavily relies on perfect ordering of certain elements. -// The key for open parenthesis, '(', is "48". -static constexpr auto s_openParenResourceKey = L"48"; - -LocalizationService ^ LocalizationService::GetInstance() -{ - if (s_singletonInstance == nullptr) - { - // Writer lock for the static maps - reader_writer_lock::scoped_lock lock(s_locServiceInstanceLock); - - if (s_singletonInstance == nullptr) - { - s_singletonInstance = ref new LocalizationService(); - } - } - return s_singletonInstance; -} - -LocalizationService::LocalizationService() -{ - m_language = ApplicationLanguages::Languages->GetAt(0); - m_flowDirection = - ResourceContext::GetForCurrentView()->QualifierValues->Lookup(L"LayoutDirection") != L"LTR" ? FlowDirection::RightToLeft : FlowDirection::LeftToRight; - - auto resourceLoader = AppResourceProvider::GetInstance(); - m_fontFamilyOverride = resourceLoader.GetResourceString(L"LocalizedFontFamilyOverride"); - - String ^ reserved = L"RESERVED_FOR_FONTLOC"; - - m_overrideFontApiValues = ((m_fontFamilyOverride != nullptr) && (m_fontFamilyOverride != reserved)); - if (m_overrideFontApiValues) - { - String ^ localizedUICaptionFontSizeFactorOverride = resourceLoader.GetResourceString(L"LocalizedUICaptionFontSizeFactorOverride"); - String ^ localizedUITextFontSizeFactorOverride = resourceLoader.GetResourceString(L"LocalizedUITextFontSizeFactorOverride"); - String ^ localizedFontWeightOverride = resourceLoader.GetResourceString(L"LocalizedFontWeightOverride"); - - // If any of the font overrides are modified then all of them need to be modified - assert(localizedFontWeightOverride != reserved); - assert(localizedUITextFontSizeFactorOverride != reserved); - assert(localizedUICaptionFontSizeFactorOverride != reserved); - - m_fontWeightOverride = ParseFontWeight(localizedFontWeightOverride); - m_uiTextFontScaleFactorOverride = _wtof(localizedUITextFontSizeFactorOverride->Data()); - m_uiCaptionFontScaleFactorOverride = _wtof(localizedUICaptionFontSizeFactorOverride->Data()); - } - - m_fontGroup = ref new LanguageFontGroup(m_language); -} - -FontWeight LocalizationService::ParseFontWeight(String ^ fontWeight) -{ - wstring weight = fontWeight->Data(); - transform(weight.begin(), weight.end(), weight.begin(), towlower); - fontWeight = ref new String(weight.c_str()); - - if (fontWeight == "black") - { - return FontWeights::Black; - } - else if (fontWeight == "bold") - { - return FontWeights::Bold; - } - else if (fontWeight == "extrablack") - { - return FontWeights::ExtraBlack; - } - else if (fontWeight == "extrabold") - { - return FontWeights::ExtraBold; - } - else if (fontWeight == "extralight") - { - return FontWeights::ExtraLight; - } - else if (fontWeight == "light") - { - return FontWeights::Light; - } - else if (fontWeight == "medium") - { - return FontWeights::Medium; - } - else if (fontWeight == "normal") - { - return FontWeights::Normal; - } - else if (fontWeight == "semibold") - { - return FontWeights::SemiBold; - } - else if (fontWeight == "semilight") - { - return FontWeights::SemiLight; - } - else if (fontWeight == "thin") - { - return FontWeights::Thin; - } - else - { - throw invalid_argument("Invalid argument: fontWeight"); - } -} - -FlowDirection LocalizationService::GetFlowDirection() -{ - return m_flowDirection; -} - -bool LocalizationService::IsRtlLayout() -{ - return m_flowDirection == FlowDirection::RightToLeft; -} - -String ^ LocalizationService::GetLanguage() -{ - return m_language; -} - -bool LocalizationService::GetOverrideFontApiValues() -{ - return m_overrideFontApiValues; -} - -FontFamily ^ LocalizationService::GetLanguageFontFamilyForType(LanguageFontType fontType) -{ - if (m_overrideFontApiValues) - { - return ref new FontFamily(m_fontFamilyOverride); - } - else - { - return ref new FontFamily(GetLanguageFont(fontType)->FontFamily); - } -} - -LanguageFont ^ LocalizationService::GetLanguageFont(LanguageFontType fontType) -{ - assert(!m_overrideFontApiValues); - assert(m_fontGroup); - - switch (fontType) - { - case LanguageFontType::UIText: - return m_fontGroup->UITextFont; - case LanguageFontType::UICaption: - return m_fontGroup->UICaptionFont; - default: - throw std::invalid_argument("fontType"); - } -} - -String ^ LocalizationService::GetFontFamilyOverride() -{ - assert(m_overrideFontApiValues); - return m_fontFamilyOverride; -} - -FontWeight LocalizationService::GetFontWeightOverride() -{ - assert(m_overrideFontApiValues); - return m_fontWeightOverride; -} - -double LocalizationService::GetFontScaleFactorOverride(LanguageFontType fontType) -{ - assert(m_overrideFontApiValues); - - switch (fontType) - { - case LanguageFontType::UIText: - return m_uiTextFontScaleFactorOverride; - case LanguageFontType::UICaption: - return m_uiCaptionFontScaleFactorOverride; - default: - throw invalid_argument("Invalid argument: fontType"); - } -} - -void LocalizationService::OnFontTypePropertyChanged(DependencyObject ^ target, LanguageFontType /*oldValue*/, LanguageFontType /*newValue*/) -{ - UpdateFontFamilyAndSize(target); -} - -void LocalizationService::OnFontWeightPropertyChanged(DependencyObject ^ target, FontWeight /*oldValue*/, FontWeight /*newValue*/) -{ - UpdateFontFamilyAndSize(target); -} - -void LocalizationService::OnFontSizePropertyChanged(DependencyObject ^ target, double /*oldValue*/, double /*newValue*/) -{ - UpdateFontFamilyAndSize(target); -} - -void LocalizationService::UpdateFontFamilyAndSize(DependencyObject ^ target) -{ - FontFamily ^ fontFamily; - FontWeight fontWeight; - bool fOverrideFontWeight = false; - double scaleFactor; - - auto service = LocalizationService::GetInstance(); - auto fontType = LocalizationService::GetFontType(target); - - if (service->GetOverrideFontApiValues()) - { - fontFamily = ref new FontFamily(service->GetFontFamilyOverride()); - scaleFactor = service->GetFontScaleFactorOverride(fontType) / 100.0; - fontWeight = service->GetFontWeightOverride(); - fOverrideFontWeight = true; - } - else - { - auto languageFont = service->GetLanguageFont(fontType); - fontFamily = ref new FontFamily(languageFont->FontFamily); - scaleFactor = languageFont->ScaleFactor / 100.0; - } - - double sizeToUse = LocalizationService::GetFontSize(target) * scaleFactor; - - auto control = dynamic_cast(target); - if (control) - { - control->FontFamily = fontFamily; - if (fOverrideFontWeight) - { - control->FontWeight = fontWeight; - } - if (sizeToUse != 0.0) - { - control->FontSize = sizeToUse; - } - else - { - control->ClearValue(Control::FontSizeProperty); - } - } - else - { - auto textBlock = dynamic_cast(target); - if (textBlock) - { - textBlock->FontFamily = fontFamily; - if (fOverrideFontWeight) - { - textBlock->FontWeight = fontWeight; - } - if (sizeToUse != 0.0) - { - textBlock->FontSize = sizeToUse; - } - else - { - textBlock->ClearValue(TextBlock::FontSizeProperty); - } - } - else - { - RichTextBlock ^ richTextBlock = dynamic_cast(target); - if (richTextBlock) - { - richTextBlock->FontFamily = fontFamily; - if (fOverrideFontWeight) - { - richTextBlock->FontWeight = fontWeight; - } - if (sizeToUse != 0.0) - { - richTextBlock->FontSize = sizeToUse; - } - else - { - richTextBlock->ClearValue(RichTextBlock::FontSizeProperty); - } - } - else - { - TextElement ^ textElement = dynamic_cast(target); - if (textElement) - { - textElement->FontFamily = fontFamily; - if (fOverrideFontWeight) - { - textElement->FontWeight = fontWeight; - } - if (sizeToUse != 0.0) - { - textElement->FontSize = sizeToUse; - } - else - { - textElement->ClearValue(TextElement::FontSizeProperty); - } - } - } - } - } -} - -// If successful, returns a formatter that respects the user's regional format settings, -// as configured by running intl.cpl. -DecimalFormatter ^ LocalizationService::GetRegionalSettingsAwareDecimalFormatter() -{ - IIterable ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers(); - if (languageIdentifiers != nullptr) - { - return ref new DecimalFormatter(languageIdentifiers, GlobalizationPreferences::HomeGeographicRegion); - } - - return ref new DecimalFormatter(); -} - -// If successful, returns a formatter that respects the user's regional format settings, -// as configured by running intl.cpl. -// -// This helper function creates a DateTimeFormatter with a TwentyFour hour clock -DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatter(_In_ String ^ format) -{ - IIterable ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers(); - if (languageIdentifiers == nullptr) - { - languageIdentifiers = ApplicationLanguages::Languages; - } - - return ref new DateTimeFormatter(format, languageIdentifiers); -} - -// If successful, returns a formatter that respects the user's regional format settings, -// as configured by running intl.cpl. -DateTimeFormatter - ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatter(_In_ String ^ format, _In_ String ^ calendarIdentifier, _In_ String ^ clockIdentifier) -{ - IIterable ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers(); - if (languageIdentifiers == nullptr) - { - languageIdentifiers = ApplicationLanguages::Languages; - } - - return ref new DateTimeFormatter(format, languageIdentifiers, GlobalizationPreferences::HomeGeographicRegion, calendarIdentifier, clockIdentifier); -} - -CurrencyFormatter ^ LocalizationService::GetRegionalSettingsAwareCurrencyFormatter() -{ - String ^ userCurrency = - (GlobalizationPreferences::Currencies->Size > 0) ? GlobalizationPreferences::Currencies->GetAt(0) : StringReference(DefaultCurrencyCode.data()); - - IIterable ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers(); - if (languageIdentifiers == nullptr) - { - languageIdentifiers = ApplicationLanguages::Languages; - } - - auto currencyFormatter = ref new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPreferences::HomeGeographicRegion); - - int fractionDigits = LocalizationSettings::GetInstance().GetCurrencyTrailingDigits(); - currencyFormatter->FractionDigits = fractionDigits; - - return currencyFormatter; -} - -IIterable ^ LocalizationService::GetLanguageIdentifiers() -{ - WCHAR currentLocale[LOCALE_NAME_MAX_LENGTH] = {}; - int result = GetUserDefaultLocaleName(currentLocale, LOCALE_NAME_MAX_LENGTH); - if (result != 0) - { - // GetUserDefaultLocaleName may return an invalid bcp47 language tag with trailing non-BCP47 friendly characters, - // which if present would start with an underscore, for example sort order - // (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx). - // Therefore, if there is an underscore in the locale name, trim all characters from the underscore onwards. - WCHAR* underscore = wcschr(currentLocale, L'_'); - if (underscore != nullptr) - { - *underscore = L'\0'; - } - - String ^ localeString = ref new String(currentLocale); - // validate if the locale we have is valid - // otherwise we fallback to the default. - if (Language::IsWellFormed(localeString)) - { - auto languageList = ref new Vector(); - languageList->Append(localeString); - return languageList; - } - } - - return nullptr; -} - -unordered_map LocalizationService::GetTokenToReadableNameMap() -{ - // Resources for the engine use numbers as keys. It's inconvenient, but also difficult to - // change given that the engine heavily relies on perfect ordering of certain elements. - // To compromise, we'll declare a map from engine resource key to automation name from the - // standard project resources. - static vector> s_parenEngineKeyResourceMap = { // Sine permutations - make_pair(L"67", L"SineDegrees"), - make_pair(L"73", L"SineRadians"), - make_pair(L"79", L"SineGradians"), - make_pair(L"70", L"InverseSineDegrees"), - make_pair(L"76", L"InverseSineRadians"), - make_pair(L"82", L"InverseSineGradians"), - make_pair(L"25", L"HyperbolicSine"), - make_pair(L"85", L"InverseHyperbolicSine"), - - // Cosine permutations - make_pair(L"68", L"CosineDegrees"), - make_pair(L"74", L"CosineRadians"), - make_pair(L"80", L"CosineGradians"), - make_pair(L"71", L"InverseCosineDegrees"), - make_pair(L"77", L"InverseCosineRadians"), - make_pair(L"83", L"InverseCosineGradians"), - make_pair(L"26", L"HyperbolicCosine"), - make_pair(L"86", L"InverseHyperbolicCosine"), - - // Tangent permutations - make_pair(L"69", L"TangentDegrees"), - make_pair(L"75", L"TangentRadians"), - make_pair(L"81", L"TangentGradians"), - make_pair(L"72", L"InverseTangentDegrees"), - make_pair(L"78", L"InverseTangentRadians"), - make_pair(L"84", L"InverseTangentGradians"), - make_pair(L"27", L"HyperbolicTangent"), - make_pair(L"87", L"InverseHyperbolicTangent"), - - // Miscellaneous Scientific functions - make_pair(L"94", L"Factorial"), - make_pair(L"35", L"DegreeMinuteSecond"), - make_pair(L"28", L"NaturalLog"), - make_pair(L"91", L"Square") - }; - - static vector> s_noParenEngineKeyResourceMap = { // Programmer mode functions - make_pair(L"9", L"LeftShift"), - make_pair(L"10", L"RightShift"), - - // Y Root scientific function - make_pair(L"16", L"YRoot") - }; - - unordered_map tokenToReadableNameMap{}; - auto resProvider = AppResourceProvider::GetInstance(); - - static const wstring openParen = resProvider.GetCEngineString(StringReference(s_openParenResourceKey))->Data(); - - for (const auto& keyPair : s_parenEngineKeyResourceMap) - { - wstring engineStr = resProvider.GetCEngineString(StringReference(keyPair.first.c_str()))->Data(); - wstring automationName = resProvider.GetResourceString(StringReference(keyPair.second.c_str()))->Data(); - - tokenToReadableNameMap.emplace(engineStr + openParen, automationName); - } - s_parenEngineKeyResourceMap.clear(); - - for (const auto& keyPair : s_noParenEngineKeyResourceMap) - { - wstring engineStr = resProvider.GetCEngineString(StringReference(keyPair.first.c_str()))->Data(); - wstring automationName = resProvider.GetResourceString(StringReference(keyPair.second.c_str()))->Data(); - - tokenToReadableNameMap.emplace(engineStr, automationName); - } - s_noParenEngineKeyResourceMap.clear(); - - // Also replace hyphens with "minus" - wstring minusText = resProvider.GetResourceString(L"minus")->Data(); - tokenToReadableNameMap.emplace(L"-", minusText); - - return tokenToReadableNameMap; -} - -String ^ LocalizationService::GetNarratorReadableToken(String ^ rawToken) -{ - static unordered_map s_tokenToReadableNameMap = GetTokenToReadableNameMap(); - - auto itr = s_tokenToReadableNameMap.find(rawToken->Data()); - if (itr == s_tokenToReadableNameMap.end()) - { - return rawToken; - } - else - { - static const String ^ openParen = AppResourceProvider::GetInstance().GetCEngineString(StringReference(s_openParenResourceKey)); - return ref new String(itr->second.c_str()) + L" " + openParen; - } -} - -String ^ LocalizationService::GetNarratorReadableString(String ^ rawString) -{ - wstringstream readableString{}; - readableString << L""; - - wstring asWstring = rawString->Data(); - for (const auto& c : asWstring) - { - readableString << LocalizationService::GetNarratorReadableToken(L"" + c)->Data(); - } - - return ref new String(readableString.str().c_str()); -} diff --git a/src/CalcViewModel/Common/LocalizationService.h b/src/CalcViewModel/Common/LocalizationService.h deleted file mode 100644 index 73b088b5..00000000 --- a/src/CalcViewModel/Common/LocalizationService.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "Utils.h" - -namespace CalculatorApp -{ - namespace Common - { - namespace LocalizationServiceProperties - { - static constexpr std::wstring_view DefaultCurrencyCode{ L"USD" }; - } - - public - enum class LanguageFontType - { - UIText, - UICaption, - }; - - public - ref class LocalizationService sealed - { - public: - DEPENDENCY_PROPERTY_OWNER(LocalizationService); - - DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT_AND_CALLBACK(LanguageFontType, FontType, LanguageFontType::UIText); - DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(double, FontSize); - - internal : static LocalizationService ^ GetInstance(); - - Windows::UI::Xaml::FlowDirection GetFlowDirection(); - bool IsRtlLayout(); - bool GetOverrideFontApiValues(); - Platform::String ^ GetLanguage(); - Windows::UI::Xaml::Media::FontFamily ^ GetLanguageFontFamilyForType(LanguageFontType fontType); - Platform::String ^ GetFontFamilyOverride(); - Windows::UI::Text::FontWeight GetFontWeightOverride(); - double GetFontScaleFactorOverride(LanguageFontType fontType); - - static Windows::Globalization::NumberFormatting::DecimalFormatter ^ GetRegionalSettingsAwareDecimalFormatter(); - static Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ GetRegionalSettingsAwareDateTimeFormatter(_In_ Platform::String ^ format); - static Windows::Globalization::DateTimeFormatting::DateTimeFormatter - ^ GetRegionalSettingsAwareDateTimeFormatter( - _In_ Platform::String ^ format, - _In_ Platform::String ^ calendarIdentifier, - _In_ Platform::String ^ clockIdentifier); - - static Windows::Globalization::NumberFormatting::CurrencyFormatter ^ GetRegionalSettingsAwareCurrencyFormatter(); - - static Platform::String ^ GetNarratorReadableToken(Platform::String ^ rawToken); - static Platform::String ^ GetNarratorReadableString(Platform::String ^ rawString); - - private: - Windows::Globalization::Fonts::LanguageFont ^ GetLanguageFont(LanguageFontType fontType); - Windows::UI::Text::FontWeight ParseFontWeight(Platform::String ^ fontWeight); - - static Windows::Foundation::Collections::IIterable ^ GetLanguageIdentifiers(); - - // Attached property callbacks - static void OnFontTypePropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, LanguageFontType oldValue, LanguageFontType newValue); - static void OnFontWeightPropertyChanged( - Windows::UI::Xaml::DependencyObject ^ target, - Windows::UI::Text::FontWeight oldValue, - Windows::UI::Text::FontWeight newValue); - static void OnFontSizePropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, double oldValue, double newValue); - - static void UpdateFontFamilyAndSize(Windows::UI::Xaml::DependencyObject ^ target); - - static std::unordered_map GetTokenToReadableNameMap(); - - private: - LocalizationService(); - - static LocalizationService ^ s_singletonInstance; - - Windows::Globalization::Fonts::LanguageFontGroup ^ m_fontGroup; - Platform::String ^ m_language; - Windows::UI::Xaml::FlowDirection m_flowDirection; - bool m_overrideFontApiValues; - Platform::String ^ m_fontFamilyOverride; - Windows::UI::Text::FontWeight m_fontWeightOverride; - double m_uiTextFontScaleFactorOverride; - double m_uiCaptionFontScaleFactorOverride; - }; - - } -} diff --git a/src/CalcViewModel/Common/LocalizationSettings.h b/src/CalcViewModel/Common/LocalizationSettings.h deleted file mode 100644 index 1b350154..00000000 --- a/src/CalcViewModel/Common/LocalizationSettings.h +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "LocalizationService.h" - -#include - -namespace CalculatorApp -{ - namespace Common - { - class LocalizationSettings - { - private: - LocalizationSettings() - { - int result = 0; - - // Use DecimalFormatter as it respects the locale and the user setting - Windows::Globalization::NumberFormatting::DecimalFormatter ^ formatter; - formatter = CalculatorApp::Common::LocalizationService::GetRegionalSettingsAwareDecimalFormatter(); - formatter->FractionDigits = 0; - formatter->IsDecimalPointAlwaysDisplayed = false; - - for (unsigned int i = 0; i < 10; i++) - { - m_digitSymbols.at(i) = formatter->FormatUInt(i)->Data()[0]; - } - - wchar_t resolvedName[LOCALE_NAME_MAX_LENGTH]; - result = ResolveLocaleName(formatter->ResolvedLanguage->Data(), resolvedName, LOCALE_NAME_MAX_LENGTH); - if (result == 0) - { - throw std::runtime_error("Unexpected error resolving locale name"); - } - else - { - m_resolvedName = resolvedName; - wchar_t decimalString[LocaleSettingBufferSize] = L""; - result = GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_SDECIMAL, decimalString, static_cast(std::size(decimalString))); - if (result == 0) - { - throw std::runtime_error("Unexpected error while getting locale info"); - } - - wchar_t groupingSymbolString[LocaleSettingBufferSize] = L""; - result = GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_STHOUSAND, groupingSymbolString, static_cast(std::size(groupingSymbolString))); - if (result == 0) - { - throw std::runtime_error("Unexpected error while getting locale info"); - } - - wchar_t numberGroupingString[LocaleSettingBufferSize] = L""; - result = GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_SGROUPING, numberGroupingString, static_cast(std::size(numberGroupingString))); - if (result == 0) - { - throw std::runtime_error("Unexpected error while getting locale info"); - } - - // Get locale info for List Separator, eg. comma is used in many locales - wchar_t listSeparatorString[4] = L""; - result = ::GetLocaleInfoEx( - LOCALE_NAME_USER_DEFAULT, - LOCALE_SLIST, - listSeparatorString, - static_cast(std::size(listSeparatorString))); // Max length of the expected return value is 4 - if (result == 0) - { - throw std::runtime_error("Unexpected error while getting locale info"); - } - - int currencyTrailingDigits = 0; - result = GetLocaleInfoEx( - m_resolvedName.c_str(), - LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER, - (LPWSTR)¤cyTrailingDigits, - sizeof(currencyTrailingDigits) / sizeof(WCHAR)); - if (result == 0) - { - throw std::runtime_error("Unexpected error while getting locale info"); - } - - // Currency symbol precedence is either 0 or 1. - // A value of 0 indicates the symbol follows the currency value. - int currencySymbolPrecedence = 1; - result = GetLocaleInfoEx( - LOCALE_NAME_USER_DEFAULT, - LOCALE_IPOSSYMPRECEDES | LOCALE_RETURN_NUMBER, - (LPWSTR)¤cySymbolPrecedence, - sizeof(currencySymbolPrecedence) / sizeof(WCHAR)); - - // As CalcEngine only supports the first character of the decimal separator, - // Only first character of the decimal separator string is supported. - m_decimalSeparator = decimalString[0]; - m_numberGroupSeparator = groupingSymbolString[0]; - m_numberGrouping = numberGroupingString; - m_listSeparator = listSeparatorString; - m_currencyTrailingDigits = currencyTrailingDigits; - m_currencySymbolPrecedence = currencySymbolPrecedence; - } - - // Get the system calendar type - // Note: This function returns 0 on failure. - // We'll ignore the failure in that case and the CalendarIdentifier would get set to GregorianCalendar. - CALID calId; - ::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER, reinterpret_cast(&calId), sizeof(calId)); - - m_calendarIdentifier = GetCalendarIdentifierFromCalid(calId); - - // Get FirstDayOfWeek Date and Time setting - wchar_t day[80] = L""; - ::GetLocaleInfoEx( - LOCALE_NAME_USER_DEFAULT, - LOCALE_IFIRSTDAYOFWEEK, // The first day in a week - reinterpret_cast(day), // Argument is of type PWSTR - static_cast(std::size(day))); // Max return size are 80 characters - - // The LOCALE_IFIRSTDAYOFWEEK integer value varies from 0, 1, .. 6 for Monday, Tuesday, ... Sunday - // DayOfWeek enum value varies from 0, 1, .. 6 for Sunday, Monday, ... Saturday - // Hence, DayOfWeek = (valueof(LOCALE_IFIRSTDAYOFWEEK) + 1) % 7 - m_firstDayOfWeek = static_cast((_wtoi(day) + 1) % 7); // static cast int to DayOfWeek enum - } - - public: - // A LocalizationSettings object is not copyable. - LocalizationSettings(const LocalizationSettings&) = delete; - LocalizationSettings& operator=(const LocalizationSettings&) = delete; - - // A LocalizationSettings object is not moveable. - LocalizationSettings(LocalizationSettings&&) = delete; - LocalizationSettings& operator=(LocalizationSettings&&) = delete; - - // Provider of the singleton LocalizationSettings instance. - static const LocalizationSettings& GetInstance() - { - static const LocalizationSettings localizationSettings; - - return localizationSettings; - } - - Platform::String ^ GetLocaleName() const - { - return ref new Platform::String(m_resolvedName.c_str()); - } - - bool IsDigitEnUsSetting() const - { - if (this->GetDigitSymbolFromEnUsDigit('0') == L'0') - { - return true; - } - return false; - } - - void LocalizeDisplayValue(_Inout_ std::wstring* stringToLocalize) const - { - if (IsDigitEnUsSetting()) - { - return; - } - - for (wchar_t& ch : *stringToLocalize) - { - if (IsEnUsDigit(ch)) - { - ch = GetDigitSymbolFromEnUsDigit(ch); - } - } - } - - Platform::String ^ GetEnglishValueFromLocalizedDigits(const std::wstring& localizedString) const - { - if (m_resolvedName == L"en-US") - { - return ref new Platform::String(localizedString.c_str()); - } - - size_t i = 0; - size_t length = localizedString.size(); - std::unique_ptr englishString(new wchar_t[length + 1]); // +1 for the null termination - - for (; i < length; ++i) - { - wchar_t ch = localizedString[i]; - if (!IsEnUsDigit(ch)) - { - for (int j = 0; j < 10; ++j) - { - if (ch == m_digitSymbols[j]) - { - ch = j.ToString()->Data()[0]; - break; - // ch = val - L'0'; - } - } - } - if (ch == m_decimalSeparator) - { - ch = L'.'; - } - englishString[i] = ch; - } - englishString[i] = '\0'; - - return ref new Platform::String(englishString.get()); - } - - bool IsEnUsDigit(const wchar_t digit) const - { - if (digit >= L'0' && digit <= L'9') - { - return true; - } - return false; - } - - bool IsLocalizedDigit(const wchar_t digit) const - { - for (auto dig : m_digitSymbols) - { - if (digit == dig) - { - return true; - } - } - return false; - } - - bool IsLocalizedHexDigit(const wchar_t digit) const - { - if (IsLocalizedDigit(digit)) - { - return true; - } - - for (auto dig : s_hexSymbols) - { - if (digit == dig) - { - return true; - } - } - - return false; - } - - wchar_t GetDigitSymbolFromEnUsDigit(wchar_t digitSymbol) const - { - assert(digitSymbol >= L'0' && digitSymbol <= L'9'); - int digit = digitSymbol - L'0'; - return m_digitSymbols.at(digit); // throws on out of range - } - - wchar_t GetDecimalSeparator() const - { - return m_decimalSeparator; - } - - wchar_t GetNumberGroupSeparator() const - { - return m_numberGroupSeparator; - } - - std::wstring GetDecimalSeparatorStr() const - { - std::wstring result; - result.push_back(m_decimalSeparator); - return result; - } - - std::wstring GetNumberGroupingSeparatorStr() const - { - std::wstring result; - result.push_back(m_numberGroupSeparator); - return result; - } - - std::wstring GetNumberGroupingStr() const - { - return m_numberGrouping; - } - - void RemoveGroupSeparators(const wchar_t* value, const size_t length, std::wstring* rawValue) const - { - rawValue->clear(); - rawValue->reserve(length); - - for (size_t i = 0; i < length; i++) - { - if (value[i] != L' ' && value[i] != m_numberGroupSeparator) - { - rawValue->append(1, value[i]); - } - } - } - - Platform::String ^ GetCalendarIdentifier() const - { - return m_calendarIdentifier; - } - - std::wstring GetListSeparator() const - { - return m_listSeparator; - } - - Windows::Globalization::DayOfWeek GetFirstDayOfWeek() const - { - return m_firstDayOfWeek; - } - - int GetCurrencyTrailingDigits() const - { - return m_currencyTrailingDigits; - } - - int GetCurrencySymbolPrecedence() const - { - return m_currencySymbolPrecedence; - } - - private: - static Platform::String^ GetCalendarIdentifierFromCalid(CALID calId) - { - switch (calId) - { - case CAL_GREGORIAN: - case CAL_GREGORIAN_ARABIC: - case CAL_GREGORIAN_ME_FRENCH: - case CAL_GREGORIAN_US: - case CAL_GREGORIAN_XLIT_ENGLISH: - case CAL_GREGORIAN_XLIT_FRENCH: - return Windows::Globalization::CalendarIdentifiers::Gregorian; - - case CAL_HEBREW: - return Windows::Globalization::CalendarIdentifiers::Hebrew; - - case CAL_HIJRI: - case CAL_PERSIAN: - return Windows::Globalization::CalendarIdentifiers::Hijri; - - case CAL_JAPAN: - return Windows::Globalization::CalendarIdentifiers::Japanese; - - case CAL_KOREA: - return Windows::Globalization::CalendarIdentifiers::Korean; - - case CAL_TAIWAN: - return Windows::Globalization::CalendarIdentifiers::Taiwan; - - case CAL_THAI: - return Windows::Globalization::CalendarIdentifiers::Thai; - - case CAL_UMALQURA: - return Windows::Globalization::CalendarIdentifiers::UmAlQura; - - // Gregorian will be the default Calendar Type - default: - return Windows::Globalization::CalendarIdentifiers::Gregorian; - } - } - - wchar_t m_decimalSeparator; - wchar_t m_numberGroupSeparator; - std::wstring m_numberGrouping; - std::array m_digitSymbols; - // Hexadecimal characters are not currently localized - static constexpr std::array s_hexSymbols{ L'A', L'B', L'C', L'D', L'E', L'F' }; - std::wstring m_listSeparator; - Platform::String ^ m_calendarIdentifier; - Windows::Globalization::DayOfWeek m_firstDayOfWeek; - int m_currencySymbolPrecedence; - std::wstring m_resolvedName; - int m_currencyTrailingDigits; - static const unsigned int LocaleSettingBufferSize = 16; - }; - } -} diff --git a/src/CalcViewModel/Common/LocalizationStringUtil.h b/src/CalcViewModel/Common/LocalizationStringUtil.h deleted file mode 100644 index 1a360bdb..00000000 --- a/src/CalcViewModel/Common/LocalizationStringUtil.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "AppResourceProvider.h" - -namespace CalculatorApp -{ - namespace Common - { - class LocalizationStringUtil - { - public: - static std::wstring GetLocalizedString(const wchar_t* pMessage, ...) - { - std::wstring returnString = L""; - const UINT32 length = 1024; - std::unique_ptr spBuffer = std::unique_ptr(new wchar_t[length]); - va_list args = NULL; - va_start(args, pMessage); - DWORD fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING, pMessage, 0, 0, spBuffer.get(), length, &args); - va_end(args); - - if (fmtReturnVal != 0) - { - returnString = spBuffer.get(); - } - - return returnString; - } - - template - static Platform::String^ GetLocalizedNarratorAnnouncement(Platform::String^ resourceKey, Platform::String^& formatVariable, T*... params) - { - EnsureInitialization(resourceKey, formatVariable); - return StringReference(GetLocalizedString(formatVariable->Data(), params...).c_str()); - } - - private: - static void EnsureInitialization(Platform::String^ resourceKey, Platform::String^& formatVariable) - { - if (resourceKey == nullptr || resourceKey->IsEmpty()) - { - return; - } - - // If the formatVariable already has a value, we don't need to set it again. Simply return. - if (formatVariable != nullptr && !formatVariable->IsEmpty()) - { - return; - } - - formatVariable = AppResourceProvider::GetInstance().GetResourceString(resourceKey); - } - }; - } -} diff --git a/src/CalcViewModel/Common/NavCategory.cpp b/src/CalcViewModel/Common/NavCategory.cpp deleted file mode 100644 index 9dfd905c..00000000 --- a/src/CalcViewModel/Common/NavCategory.cpp +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NavCategory.h" -#include "AppResourceProvider.h" -#include "Common/LocalizationStringUtil.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace Platform; -using namespace Platform::Collections; -using namespace std; -using namespace Windows::Foundation::Collections; - -namespace UCM = UnitConversionManager; - -// Calculator categories always support negative and positive. -static constexpr bool SUPPORTS_ALL = true; - -// Converter categories usually only support positive. -static constexpr bool SUPPORTS_NEGATIVE = true; -static constexpr bool POSITIVE_ONLY = false; - -// The order of items in this list determines the order of groups in the menu. -static constexpr array s_categoryGroupManifest = { - NavCategoryGroupInitializer{ CategoryGroupType::Calculator, L"CalculatorModeTextCaps", L"CalculatorModeText", L"CalculatorModePluralText" }, - NavCategoryGroupInitializer{ CategoryGroupType::Converter, L"ConverterModeTextCaps", L"ConverterModeText", L"ConverterModePluralText" } -}; - -// vvv THESE CONSTANTS SHOULD NEVER CHANGE vvv -static constexpr int STANDARD_ID = 0; -static constexpr int SCIENTIFIC_ID = 1; -static constexpr int PROGRAMMER_ID = 2; -static constexpr int DATE_ID = 3; -static constexpr int VOLUME_ID = 4; -static constexpr int LENGTH_ID = 5; -static constexpr int WEIGHT_ID = 6; -static constexpr int TEMPERATURE_ID = 7; -static constexpr int ENERGY_ID = 8; -static constexpr int AREA_ID = 9; -static constexpr int SPEED_ID = 10; -static constexpr int TIME_ID = 11; -static constexpr int POWER_ID = 12; -static constexpr int DATA_ID = 13; -static constexpr int PRESSURE_ID = 14; -static constexpr int ANGLE_ID = 15; -static constexpr int CURRENCY_ID = 16; -// ^^^ 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 = { 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::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 }, - NavCategoryInitializer{ ViewMode::Weight, - WEIGHT_ID, - L"Weight and Mass", - L"CategoryName_Weight", - L"\uF4C1", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Temperature, - TEMPERATURE_ID, - L"Temperature", - L"CategoryName_Temperature", - L"\uE7A3", - CategoryGroupType::Converter, - MyVirtualKey::None, - SUPPORTS_NEGATIVE }, - NavCategoryInitializer{ ViewMode::Energy, - ENERGY_ID, - L"Energy", - L"CategoryName_Energy", - L"\uECAD", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Area, - AREA_ID, - L"Area", - L"CategoryName_Area", - L"\uE809", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Speed, - SPEED_ID, - L"Speed", - L"CategoryName_Speed", - L"\uEADA", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Time, - TIME_ID, - L"Time", - L"CategoryName_Time", - L"\uE917", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Power, - POWER_ID, - L"Power", - L"CategoryName_Power", - L"\uE945", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Data, - DATA_ID, - L"Data", - L"CategoryName_Data", - L"\uF20F", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Pressure, - PRESSURE_ID, - L"Pressure", - L"CategoryName_Pressure", - L"\uEC4A", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY }, - NavCategoryInitializer{ ViewMode::Angle, - ANGLE_ID, - L"Angle", - L"CategoryName_Angle", - L"\uF515", - CategoryGroupType::Converter, - MyVirtualKey::None, - POSITIVE_ONLY } }; - -// This function should only be used when storing the mode to app data. -int NavCategory::Serialize(ViewMode mode) -{ - auto iter = - find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; }); - - return (iter != s_categoryManifest.end()) ? iter->serializationId : -1; -} - -// This function should only be used when restoring the mode from app data. -ViewMode NavCategory::Deserialize(Platform::Object ^ obj) -{ - // If we cast directly to ViewMode we will fail - // because we technically store an int. - // Need to cast to int, then ViewMode. - auto boxed = dynamic_cast ^>(obj); - if (boxed != nullptr) - { - int serializationId = boxed->Value; - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [serializationId](const NavCategoryInitializer& initializer) { - return initializer.serializationId == serializationId; - }); - - if (iter != s_categoryManifest.end()) - { - return iter->viewMode; - } - } - - return ViewMode::None; -} - -bool NavCategory::IsValidViewMode(ViewMode mode) -{ - auto iter = - find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; }); - - return iter != s_categoryManifest.end(); -} - -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); -} - -bool NavCategory::IsDateCalculatorViewMode(ViewMode mode) -{ - return mode == ViewMode::Date; -} - -bool NavCategory::IsConverterViewMode(ViewMode mode) -{ - return IsModeInCategoryGroup(mode, CategoryGroupType::Converter); -} - -bool NavCategory::IsModeInCategoryGroup(ViewMode mode, CategoryGroupType type) -{ - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, type](const NavCategoryInitializer& initializer) { - return initializer.viewMode == mode && initializer.groupType == type; - }); - - return iter != s_categoryManifest.end(); -} - -String ^ NavCategory::GetFriendlyName(ViewMode mode) -{ - auto iter = - find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; }); - - return (iter != s_categoryManifest.end()) ? StringReference(iter->friendlyName) : L"None"; -} - -ViewMode NavCategory::GetViewModeForFriendlyName(String ^ name) -{ - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [name](const NavCategoryInitializer& initializer) { - return wcscmp(initializer.friendlyName, name->Data()) == 0; - }); - - return (iter != s_categoryManifest.end()) ? iter->viewMode : ViewMode::None; -} - -String ^ NavCategory::GetNameResourceKey(ViewMode mode) -{ - auto iter = - find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; }); - - return (iter != s_categoryManifest.end()) ? StringReference(iter->nameResourceKey) + "Text" : nullptr; -} - -CategoryGroupType NavCategory::GetGroupType(ViewMode mode) -{ - auto iter = - find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; }); - - return (iter != s_categoryManifest.end()) ? iter->groupType : CategoryGroupType::None; -} - -// GetIndex is 0-based, GetPosition is 1-based -int NavCategory::GetIndex(ViewMode mode) -{ - int position = NavCategory::GetPosition(mode); - return max(-1, position - 1); -} - -int NavCategory::GetFlatIndex(ViewMode mode) -{ - int index = -1; - CategoryGroupType type = CategoryGroupType::None; - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, &type, &index](const NavCategoryInitializer& initializer) { - index++; - if (initializer.groupType != type) - { - type = initializer.groupType; - index++; - } - - return initializer.viewMode == mode; - }); - - return (iter != s_categoryManifest.end()) ? index : -1; -} - -// GetIndex is 0-based, GetPosition is 1-based -int NavCategory::GetIndexInGroup(ViewMode mode, CategoryGroupType type) -{ - int index = -1; - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, type, &index](const NavCategoryInitializer& initializer) { - if (initializer.groupType == type) - { - index++; - return initializer.viewMode == mode; - } - - return false; - }); - - return (iter != s_categoryManifest.end()) ? index : -1; -} - -// GetIndex is 0-based, GetPosition is 1-based -int NavCategory::GetPosition(ViewMode mode) -{ - int position = 0; - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, &position](const NavCategoryInitializer& initializer) { - position++; - return initializer.viewMode == mode; - }); - - return (iter != s_categoryManifest.end()) ? position : -1; -} - -ViewMode NavCategory::GetViewModeForVirtualKey(MyVirtualKey virtualKey) -{ - auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [virtualKey](const NavCategoryInitializer& initializer) { - return initializer.virtualKey == virtualKey; - }); - - return (iter != s_categoryManifest.end()) ? iter->viewMode : ViewMode::None; -} - -vector NavCategory::GetCategoryAcceleratorKeys() -{ - vector accelerators{}; - for (auto category : s_categoryManifest) - { - if (category.virtualKey != MyVirtualKey::None) - { - accelerators.push_back(category.virtualKey); - } - } - - return accelerators; -} - -NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer) - : m_Categories(ref new Vector()) -{ - m_GroupType = groupInitializer.type; - - auto resProvider = AppResourceProvider::GetInstance(); - String ^ headerResourceKey = StringReference(groupInitializer.headerResourceKey); - String ^ modeResourceKey = StringReference(groupInitializer.modeResourceKey); - String ^ automationResourceKey = StringReference(groupInitializer.automationResourceKey); - m_Name = resProvider.GetResourceString(headerResourceKey); - String ^ groupMode = resProvider.GetResourceString(modeResourceKey); - String ^ automationName = resProvider.GetResourceString(automationResourceKey); - - String ^ navCategoryHeaderAutomationNameFormat = resProvider.GetResourceString(L"NavCategoryHeader_AutomationNameFormat"); - m_AutomationName = - ref new String(LocalizationStringUtil::GetLocalizedString(navCategoryHeaderAutomationNameFormat->Data(), automationName->Data()).c_str()); - - String ^ navCategoryItemAutomationNameFormat = resProvider.GetResourceString(L"NavCategoryItem_AutomationNameFormat"); - - for (const NavCategoryInitializer& categoryInitializer : s_categoryManifest) - { - if (categoryInitializer.groupType == groupInitializer.type) - { - String ^ nameResourceKey = StringReference(categoryInitializer.nameResourceKey); - String ^ categoryName = resProvider.GetResourceString(nameResourceKey + "Text"); - String ^ categoryAutomationName = ref new String( - LocalizationStringUtil::GetLocalizedString(navCategoryItemAutomationNameFormat->Data(), categoryName->Data(), m_Name->Data()).c_str()); - - m_Categories->Append(ref new NavCategory( - categoryName, - categoryAutomationName, - StringReference(categoryInitializer.glyph), - resProvider.GetResourceString(nameResourceKey + "AccessKey"), - groupMode, - categoryInitializer.viewMode, - categoryInitializer.supportsNegative)); - } - } -} - -IObservableVector ^ NavCategoryGroup::CreateMenuOptions() -{ - auto menuOptions = ref new Vector(); - menuOptions->Append(CreateCalculatorCategory()); - menuOptions->Append(CreateConverterCategory()); - return menuOptions; -} - -NavCategoryGroup ^ NavCategoryGroup::CreateCalculatorCategory() -{ - return ref new NavCategoryGroup(s_categoryGroupManifest.at(0)); -} - -NavCategoryGroup ^ NavCategoryGroup::CreateConverterCategory() -{ - return ref new NavCategoryGroup(s_categoryGroupManifest.at(1)); -} - -vector NavCategoryGroup::GetInitializerCategoryGroup(CategoryGroupType groupType) -{ - vector initializers{}; - copy_if(begin(s_categoryManifest), end(s_categoryManifest), back_inserter(initializers), [groupType](const NavCategoryInitializer& initializer) { - return initializer.groupType == groupType; - }); - - return initializers; -} - -String ^ NavCategoryGroup::GetHeaderResourceKey(CategoryGroupType type) -{ - auto iter = find_if(begin(s_categoryGroupManifest), end(s_categoryGroupManifest), [type](const NavCategoryGroupInitializer& initializer) { - return initializer.type == type; - }); - - return (iter != s_categoryGroupManifest.end()) ? StringReference(iter->headerResourceKey) : nullptr; -} diff --git a/src/CalcViewModel/Common/NavCategory.h b/src/CalcViewModel/Common/NavCategory.h deleted file mode 100644 index b1cf1d3d..00000000 --- a/src/CalcViewModel/Common/NavCategory.h +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -/* The NavCategory group of classes and enumerations is intended to serve - * as a single location for storing metadata about a navigation mode. - * - * These .h and .cpp files: - * - Define the ViewMode enumeration which is used for setting the mode of the app. - * - Define a list of metadata associated with each ViewMode. - * - Define the order of groups and items in the navigation menu. - * - Provide a static helper function for creating the navigation menu options. - * - Provide static helper functions for querying information about a given ViewMode. - */ - -#pragma once - -#include "Utils.h" -#include "MyVirtualKey.h" - -namespace CalculatorApp -{ - namespace Common - { - // Don't change the order of these enums - // and definitely don't use int arithmetic - // to change modes. - public - enum class ViewMode - { - None = -1, - Standard = 0, - Scientific = 1, - Programmer = 2, - Date = 3, - Volume = 4, - Length = 5, - Weight = 6, - Temperature = 7, - Energy = 8, - Area = 9, - Speed = 10, - Time = 11, - Power = 12, - Data = 13, - Pressure = 14, - Angle = 15, - Currency = 16 - }; - - public - enum class CategoryGroupType - { - None = -1, - Calculator = 0, - Converter = 1 - }; - - private - struct NavCategoryInitializer - { - constexpr NavCategoryInitializer( - ViewMode mode, - int id, - wchar_t const* name, - wchar_t const* nameKey, - wchar_t const* glyph, - CategoryGroupType group, - MyVirtualKey vKey, - bool categorySupportsNegative) - : viewMode(mode) - , serializationId(id) - , friendlyName(name) - , nameResourceKey(nameKey) - , glyph(glyph) - , groupType(group) - , virtualKey(vKey) - , supportsNegative(categorySupportsNegative) - { - } - - const ViewMode viewMode; - const int serializationId; - const wchar_t* const friendlyName; - const wchar_t* const nameResourceKey; - const wchar_t* const glyph; - const CategoryGroupType groupType; - const MyVirtualKey virtualKey; - const bool supportsNegative; - }; - - private - struct NavCategoryGroupInitializer - { - constexpr NavCategoryGroupInitializer(CategoryGroupType t, wchar_t const* h, wchar_t const* n, wchar_t const* a) - : type(t) - , headerResourceKey(h) - , modeResourceKey(n) - , automationResourceKey(a) - { - } - - const CategoryGroupType type; - const wchar_t* headerResourceKey; - const wchar_t* modeResourceKey; - const wchar_t* automationResourceKey; - }; - - [Windows::UI::Xaml::Data::Bindable] public ref class NavCategory sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - public: - OBSERVABLE_OBJECT(); - - property Platform::String - ^ Name { Platform::String ^ get() { return m_name; } } - - property Platform::String - ^ AutomationName { Platform::String ^ get() { return m_automationName; } } - - property Platform::String - ^ Glyph { Platform::String ^ get() { return m_glyph; } } - - property int Position - { - int get() - { - return m_position; - } - } - - property ViewMode Mode - { - ViewMode get() - { - return m_viewMode; - } - } - - property Platform::String - ^ AutomationId { Platform::String ^ get() { return m_viewMode.ToString(); } } - - property Platform::String - ^ AccessKey { Platform::String ^ get() { return m_accessKey; } } - - property bool SupportsNegative - { - bool get() - { - return m_supportsNegative; - } - } - - // For saving/restoring last mode used. - static int Serialize(ViewMode mode); - static ViewMode Deserialize(Platform::Object ^ obj); - static ViewMode GetViewModeForFriendlyName(Platform::String ^ name); - - static bool IsValidViewMode(ViewMode mode); - static bool IsCalculatorViewMode(ViewMode mode); - static bool IsDateCalculatorViewMode(ViewMode mode); - static bool IsConverterViewMode(ViewMode mode); - - static Platform::String ^ GetFriendlyName(ViewMode mode); - static Platform::String ^ GetNameResourceKey(ViewMode mode); - static CategoryGroupType GetGroupType(ViewMode mode); - - // GetIndex is 0-based, GetPosition is 1-based - static int GetIndex(ViewMode mode); - static int GetFlatIndex(ViewMode mode); - static int GetIndexInGroup(ViewMode mode, CategoryGroupType type); - static int GetPosition(ViewMode mode); - - static ViewMode GetViewModeForVirtualKey(MyVirtualKey virtualKey); - - internal : NavCategory( - Platform::String ^ name, - Platform::String ^ automationName, - Platform::String ^ glyph, - Platform::String ^ accessKey, - Platform::String ^ mode, - ViewMode viewMode, - bool supportsNegative) - : m_name(name) - , m_automationName(automationName) - , m_glyph(glyph) - , m_accessKey(accessKey) - , m_mode(mode) - , m_viewMode(viewMode) - , m_supportsNegative(supportsNegative) - { - m_position = NavCategory::GetPosition(m_viewMode); - } - - static std::vector GetCategoryAcceleratorKeys(); - - private: - static bool IsModeInCategoryGroup(ViewMode mode, CategoryGroupType groupType); - - ViewMode m_viewMode; - Platform::String ^ m_name; - Platform::String ^ m_automationName; - Platform::String ^ m_glyph; - Platform::String ^ m_accessKey; - Platform::String ^ m_mode; - int m_position; - bool m_supportsNegative; - }; - - [Windows::UI::Xaml::Data::Bindable] public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - public: - OBSERVABLE_OBJECT(); - OBSERVABLE_PROPERTY_R(Platform::String ^, Name); - OBSERVABLE_PROPERTY_R(Platform::String ^, AutomationName); - OBSERVABLE_PROPERTY_R(CategoryGroupType, GroupType); - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Categories); - - static Windows::Foundation::Collections::IObservableVector ^ CreateMenuOptions(); - - static Platform::String ^ GetHeaderResourceKey(CategoryGroupType type); - - internal : static NavCategoryGroup ^ CreateCalculatorCategory(); - static NavCategoryGroup ^ CreateConverterCategory(); - - private: - NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer); - - static std::vector GetInitializerCategoryGroup(CategoryGroupType groupType); - }; - } -} diff --git a/src/CalcViewModel/Common/NetworkManager.cpp b/src/CalcViewModel/Common/NetworkManager.cpp deleted file mode 100644 index 8bf3835a..00000000 --- a/src/CalcViewModel/Common/NetworkManager.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NetworkManager.h" - -using namespace CalculatorApp; -using namespace Platform; -using namespace Windows::Networking::Connectivity; - -NetworkManager::NetworkManager() -{ - m_NetworkStatusChangedToken = NetworkInformation::NetworkStatusChanged += - ref new NetworkStatusChangedEventHandler(this, &NetworkManager::OnNetworkStatusChange, CallbackContext::Same); -} - -NetworkManager::~NetworkManager() -{ - NetworkInformation::NetworkStatusChanged -= m_NetworkStatusChangedToken; -} - -NetworkAccessBehavior NetworkManager::GetNetworkAccessBehavior() -{ - NetworkAccessBehavior behavior = NetworkAccessBehavior::Offline; - ConnectionProfile ^ connectionProfile = NetworkInformation::GetInternetConnectionProfile(); - if (connectionProfile != nullptr) - { - NetworkConnectivityLevel connectivityLevel = connectionProfile->GetNetworkConnectivityLevel(); - if (connectivityLevel == NetworkConnectivityLevel::InternetAccess || connectivityLevel == NetworkConnectivityLevel::ConstrainedInternetAccess) - { - ConnectionCost ^ connectionCost = connectionProfile->GetConnectionCost(); - behavior = ConvertCostInfoToBehavior(connectionCost); - } - } - - return behavior; -} - -void NetworkManager::OnNetworkStatusChange(_In_ Object ^ /*sender*/) -{ - NetworkBehaviorChanged(GetNetworkAccessBehavior()); -} - -// See app behavior guidelines at https://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj835821(v=win.10).aspx -NetworkAccessBehavior NetworkManager::ConvertCostInfoToBehavior(_In_ ConnectionCost ^ connectionCost) -{ - if (connectionCost->Roaming || connectionCost->OverDataLimit || connectionCost->NetworkCostType == NetworkCostType::Variable - || connectionCost->NetworkCostType == NetworkCostType::Fixed) - { - return NetworkAccessBehavior::OptIn; - } - - return NetworkAccessBehavior::Normal; -} diff --git a/src/CalcViewModel/Common/NetworkManager.h b/src/CalcViewModel/Common/NetworkManager.h deleted file mode 100644 index 51903d94..00000000 --- a/src/CalcViewModel/Common/NetworkManager.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ -public - enum class NetworkAccessBehavior - { - Normal = 0, - OptIn = 1, - Offline = 2 - }; - -public - delegate void NetworkBehaviorChangedHandler(NetworkAccessBehavior behavior); - -public - ref class NetworkManager sealed - { - public: - NetworkManager(); - - static NetworkAccessBehavior GetNetworkAccessBehavior(); - - event NetworkBehaviorChangedHandler ^ NetworkBehaviorChanged; - - private: - ~NetworkManager(); - - void OnNetworkStatusChange(_In_ Platform::Object ^ sender); - static NetworkAccessBehavior ConvertCostInfoToBehavior(_In_ Windows::Networking::Connectivity::ConnectionCost ^ connectionCost); - - private: - Windows::Foundation::EventRegistrationToken m_NetworkStatusChangedToken; - }; -} diff --git a/src/CalcViewModel/Common/TraceActivity.h b/src/CalcViewModel/Common/TraceActivity.h deleted file mode 100644 index 41046a63..00000000 --- a/src/CalcViewModel/Common/TraceActivity.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - constexpr int64_t WINEVENT_KEYWORD_RESPONSE_TIME = 0x1000000000000; - - // RAII wrapper that automatically sends the Stop event when the class gets destructed. - class TraceActivity - { - public: - TraceActivity() - : m_channel(nullptr) - , m_activity(nullptr) - , m_fields(nullptr) - { - } - - TraceActivity( - winrt::Windows::Foundation::Diagnostics::LoggingChannel channel, - std::wstring_view activityName, - winrt::Windows::Foundation::Diagnostics::LoggingFields fields) - : m_channel(channel) - , m_activityName(activityName) - , m_fields(fields) - , m_activity(nullptr) - { - // Write the activity's START event. Note that you must not specify keyword - // or level for START and STOP events because they always use the activity's - // keyword and level. - m_activity = m_channel.StartActivity( - m_activityName, - m_fields, - winrt::Windows::Foundation::Diagnostics::LoggingLevel::Verbose, - winrt::Windows::Foundation::Diagnostics::LoggingOptions(WINEVENT_KEYWORD_RESPONSE_TIME)); - } - - ~TraceActivity() - { - if (m_activity != nullptr) - { - // Write the activity's STOP event. - m_activity.StopActivity(m_activityName, m_fields); - m_activity = nullptr; - } - } - - private: - std::wstring m_activityName; - winrt::Windows::Foundation::Diagnostics::LoggingChannel m_channel; - winrt::Windows::Foundation::Diagnostics::LoggingFields m_fields; - winrt::Windows::Foundation::Diagnostics::LoggingActivity m_activity; - }; -} diff --git a/src/CalcViewModel/Common/TraceLogger.cpp b/src/CalcViewModel/Common/TraceLogger.cpp deleted file mode 100644 index f7d32d99..00000000 --- a/src/CalcViewModel/Common/TraceLogger.cpp +++ /dev/null @@ -1,1017 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "TraceLogger.h" -#include "NetworkManager.h" -#include "CalculatorButtonUser.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace Concurrency; -using namespace std; -using namespace winrt; -using namespace winrt::Windows::Foundation; -using namespace winrt::Windows::Foundation::Diagnostics; -using namespace winrt::Windows::Globalization; -using namespace winrt::Windows::Globalization::DateTimeFormatting; -using namespace winrt::Windows::System::UserProfile; - -namespace CalculatorApp -{ - static multimap> s_memoryMap; - - static constexpr array s_programmerType{ L"N/A", L"QwordType", L"DwordType", L"WordType", L"ByteType", - L"HexBase", L"DecBase", L"OctBase", L"BinBase" }; - static reader_writer_lock s_traceLoggerLock; - - // Telemetry events. Uploaded to asimov. - constexpr auto EVENT_NAME_DEBUG = L"Debug"; - constexpr auto EVENT_NAME_ERROR = L"ErrorMessage"; - constexpr auto EVENT_NAME_APP_PRELAUNCHED_BY_SYSTEM = L"AppPrelaunchedBySystem"; - constexpr auto EVENT_NAME_PRELAUNCHED_APP_ACTIVATED_BY_USER = L"PrelaunchedAppActivatedByUser"; - constexpr auto EVENT_NAME_APP_LAUNCH_BEGIN = L"AppLaunchBegin"; - constexpr auto EVENT_NAME_APP_LAUNCH_END = L"AppLaunchEnd"; - constexpr auto EVENT_NAME_APP_RESUME_END = L"AppResumeEnd"; - constexpr auto EVENT_NAME_PREVIOUS_STATE_WINDOW_ON_CREATION = L"PreviousStateOnWindowCreation"; - constexpr auto EVENT_NAME_SIZE_ON_SUSPENSION = L"CalculatorSizeOnSuspension"; - constexpr auto EVENT_NAME_CALCULATOR_VIEWED_IN_SESSION = L"CalculatorViewedInSession"; - constexpr auto EVENT_NAME_DATE_CALCULATOR_VIEWED_IN_SESSION = L"DateCalculatorViewedInSession"; - constexpr auto EVENT_NAME_CONVERTER_VIEWED_IN_SESSION = L"ConverterViewedInSession"; - constexpr auto EVENT_NAME_MODE_CHANGE_BEGIN = L"ModeChangeBegin"; - constexpr auto EVENT_NAME_MODE_CHANGE_END = L"ModeChangeEnd"; - constexpr auto EVENT_NAME_HISTORY_BODY_OPENED = L"HistoryBodyOpened"; - constexpr auto EVENT_NAME_HISTORY_ITEM_LOAD_BEGIN = L"HistoryItemLoadBegin"; - constexpr auto EVENT_NAME_HISTORY_ITEM_LOAD_END = L"HistoryItemLoadEnd"; - constexpr auto EVENT_NAME_HISTORY_FLYOUT_OPEN_BEGIN = L"HistoryFlyoutOpenBegin"; - constexpr auto EVENT_NAME_HISTORY_FLYOUT_OPEN_END = L"HistoryFlyoutOpenEnd"; - constexpr auto EVENT_NAME_NEW_WINDOW_CREATION_BEGIN = L"NewWindowCreationBegin"; - constexpr auto EVENT_NAME_NEW_WINDOW_CREATION_END = L"NewWindowCreationEnd"; - constexpr auto EVENT_NAME_HISTORY_CLEAR = L"HistoryClearBegin"; - constexpr auto EVENT_NAME_MULTIPLE_MEMORY_USED = L"MultipleMemoryUsed"; - constexpr auto EVENT_NAME_SINGLE_MEMORY_USED = L"SingleMemoryUsed"; - constexpr auto EVENT_NAME_SHARED_MEMORY_USED = L"SharedMemoryUsed"; - constexpr auto EVENT_NAME_MEMORY_BODY_OPENED = L"MemoryBodyOpened"; - constexpr auto EVENT_NAME_MEMORY_FLYOUT_OPEN_BEGIN = L"MemoryFlyoutOpenBegin"; - constexpr auto EVENT_NAME_MEMORY_FLYOUT_OPEN_END = L"MemoryFlyoutOpenEnd"; - constexpr auto EVENT_NAME_MEMORY_CLEAR_ALL = L"MemoryClearAll"; - constexpr auto EVENT_NAME_INVALID_PASTED_INPUT_OCCURRED = L"InvalidPastedInputOccurred"; - constexpr auto EVENT_NAME_VALID_INPUT_PASTED = L"ValidInputPasted"; - constexpr auto EVENT_NAME_BITFLIP_PANE_CLICKED = L"BitFlipPaneClicked"; - constexpr auto EVENT_NAME_BITFLIP_BUTTONS_USED = L"BitFlipToggleButtonUsed"; - constexpr auto EVENT_NAME_ANGLE_BUTTONS_USED = L"AngleButtonUsedInSession"; - constexpr auto EVENT_NAME_HYP_BUTTON_USED = L"HypButtonUsedInSession"; - constexpr auto EVENT_NAME_FUNCTION_USAGE = L"FunctionUsageInSession"; - constexpr auto EVENT_NAME_BITLENGTH_BUTTON_USED = L"BitLengthButtonUsed"; - constexpr auto EVENT_NAME_RADIX_BUTTON_USED = L"RadixButtonUsed"; - constexpr auto EVENT_NAME_MAX_WINDOW_COUNT = L"MaxWindowCountInSession"; - constexpr auto EVENT_NAME_WINDOW_LAUNCHED_PROTOCOL = L"WindowActivatedThroughProtocol"; - constexpr auto EVENT_NAME_WINDOW_LAUNCHED_TILESEARCH = L"WindowLaunchedThroughTile"; - constexpr auto EVENT_NAME_DATE_DIFFERENCE_USED = L"DateDifferenceModeUsed"; - constexpr auto EVENT_NAME_DATE_ADD_SUBTRACT_USED = L"DateAddSubtractModeUsed"; - constexpr auto EVENT_NAME_DATE_DIFFERENCE_FOUND = L"DateDifferenceFound"; - constexpr auto EVENT_NAME_HIDE_IF_SHOWN = L"HideIfShown"; - constexpr auto EVENT_NAME_ABOUT_FLYOUT_OPENED = L"AboutFlyoutOpened"; - constexpr auto EVENT_NAME_NAV_BAR_OPENED = L"NavBarOpened"; - constexpr auto EVENT_NAME_CORE_WINDOW_WAS_NULL = L"CoreWindowWasNull"; - - constexpr auto EVENT_NAME_EXCEPTION = L"Exception"; - - constexpr auto PDT_PRIVACY_DATA_TAG = L"PartA_PrivTags"; - constexpr auto PDT_PRODUCT_AND_SERVICE_USAGE = 0x0000'0000'0200'0000u; - -#ifdef SEND_TELEMETRY - // c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords - // c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords - constexpr int64_t MICROSOFT_KEYWORD_CRITICAL_DATA = 0x0000800000000000; // Bit 47 - constexpr int64_t MICROSOFT_KEYWORD_MEASURES = 0x0000400000000000; // Bit 46 - constexpr int64_t MICROSOFT_KEYWORD_TELEMETRY = 0x0000200000000000; // Bit 45 - constexpr int64_t MICROSOFT_KEYWORD_RESERVED_44 = 0x0000100000000000; // Bit 44 (reserved for future assignment) -#else - // define all Keyword options as 0 when we do not want to upload app telemetry - constexpr int64_t MICROSOFT_KEYWORD_CRITICAL_DATA = 0; - constexpr int64_t MICROSOFT_KEYWORD_MEASURES = 0; - constexpr int64_t MICROSOFT_KEYWORD_TELEMETRY = 0; - constexpr int64_t MICROSOFT_KEYWORD_RESERVED_44 = 0; -#endif - -#pragma region TraceLogger setup and cleanup - - TraceLogger::TraceLogger() - : g_calculatorProvider( - L"MicrosoftCalculator", - LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), // Microsoft Telemetry group - GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 }) - , // Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0} - m_appLaunchActivity{ nullptr } - { - // initialize the function array - InitFunctionLogArray(); - } - - TraceLogger::~TraceLogger() - { - } - - TraceLogger& TraceLogger::GetInstance() - { - static TraceLogger s_selfInstance; - return s_selfInstance; - } - - bool TraceLogger::GetTraceLoggingProviderEnabled() const - { - return g_calculatorProvider.Enabled(); - } - -#pragma region Tracing methods - void TraceLogger::LogTelemetryEvent(wstring_view eventName, LoggingFields fields) const - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_TELEMETRY)); - } - - void TraceLogger::LogMeasureEvent(wstring_view eventName, LoggingFields fields) const - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_MEASURES)); - } - - void TraceLogger::LogCriticalDataEvent(wstring_view eventName, LoggingFields fields) const - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_CRITICAL_DATA)); - } - - void TraceLogger::LogPerformanceEvent(wstring_view eventName, LoggingFields fields) const - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(WINEVENT_KEYWORD_RESPONSE_TIME)); - } - - void TraceLogger::LogInfoEvent(wstring_view eventName, LoggingFields fields) const - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Information); - } - - unique_ptr TraceLogger::CreateTraceActivity(wstring_view eventName, LoggingFields fields) const - { - return make_unique(g_calculatorProvider, eventName, fields); - } -#pragma endregion - - void TraceLogger::InsertIntoMemoryMap(int windowId, bool isStandard, bool isScientific, bool isProgrammer) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - auto iterMap = s_memoryMap.find(windowId); - if (iterMap == s_memoryMap.end()) - { - s_memoryMap.insert(std::make_pair(windowId, vector())); - iterMap = s_memoryMap.find(windowId); - } - - if (isScientific) - { - iterMap->second.insert(iterMap->second.begin(), L"Scientific"); - } - else if (isProgrammer) - { - iterMap->second.insert(iterMap->second.begin(), L"Programmer"); - } - else if (isStandard) - { - iterMap->second.insert(iterMap->second.begin(), L"Standard"); - } - } - - void TraceLogger::UpdateMemoryMap(int windowId, int memoryPosition, bool isStandard, bool isScientific, bool isProgrammer) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - auto iterMap = s_memoryMap.find(windowId); - assert(iterMap != s_memoryMap.end()); - assert(iterMap->second.size() >= (unsigned int)memoryPosition); - - if (isScientific) - { - iterMap->second[memoryPosition] = L"Scientific"; - } - else if (isProgrammer) - { - iterMap->second[memoryPosition] = L"Programmer"; - } - else if (isStandard) - { - iterMap->second[memoryPosition] = L"Standard"; - } - } - - void TraceLogger::DeleteFromMemoryMap(int windowId, int memoryPosition) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - auto iterMap = s_memoryMap.find(windowId); - assert(iterMap != s_memoryMap.end()); - - iterMap->second.erase(iterMap->second.begin() + memoryPosition); - } - - // return true if windowId is logged once else return false - bool TraceLogger::UpdateWindowIdLog(int windowId) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - if (windowIdLog.find(windowId) == windowIdLog.end()) - { - return false; - } - if (windowIdLog[windowId] == false) - { - windowIdLog[windowId] = true; - return true; - } - else - { - return false; - } - } - - // call comes here at the time of ApplicationViewModel initialisation - void TraceLogger::LogCalculatorModeViewed(ViewMode mode, int windowId) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - // store windowId in windowIdLog which says we have logged mode for the present windowId. - if (windowIdLog.find(windowId) == windowIdLog.end()) - { - windowIdLog.insert(pair(windowId, false)); - } - // if the event is not logged already for the present mode - if (currentMode != mode) - { - currentMode = mode; - - LoggingFields fields{}; - fields.AddString(L"CalculatorMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_CALCULATOR_VIEWED_IN_SESSION, fields); - } - } - - // call comes here at the time of ApplicationViewModel initialization - void TraceLogger::LogDateCalculatorModeViewed(ViewMode mode, int windowId) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - // store windowId in windowIdLog which says we have logged mode for the present windowId. - if (windowIdLog.find(windowId) == windowIdLog.end()) - { - windowIdLog.insert(pair(windowId, false)); - } - // if the event is not logged already for the present mode - if (currentMode != mode) - { - currentMode = mode; - - LoggingFields fields{}; - fields.AddString(L"DateCalculatorMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_DATE_CALCULATOR_VIEWED_IN_SESSION, fields); - } - } - - // call comes here at the time of ApplicationViewModel initialization - void TraceLogger::LogConverterModeViewed(ViewMode mode, int windowId) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - if (windowIdLog.find(windowId) == windowIdLog.end()) - { - windowIdLog.insert(pair(windowId, false)); - } - // if the event is not logged already for the present mode - if (currentMode != mode) - { - currentMode = mode; - - LoggingFields fields{}; - fields.AddString(L"ConverterMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_CONVERTER_VIEWED_IN_SESSION, fields); - } - } - - void TraceLogger::LogSharedMemoryUsed(wstring_view fromMode, wstring_view toMode, unsigned int memorySize) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"FromMode", fromMode); - fields.AddString(L"ToMode", toMode); - fields.AddUInt32(L"MemoryListSize", memorySize); - LogTelemetryEvent(EVENT_NAME_SHARED_MEMORY_USED, fields); - } - - void TraceLogger::LogBitFlipPaneClicked() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_BITFLIP_PANE_CLICKED, fields); - } - - void TraceLogger::LogBitFlipUsed() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_BITFLIP_BUTTONS_USED, fields); - } - - void TraceLogger::LogAppLaunchStart() - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - if (!isAppLaunchBeginLogged) - { - m_appLaunchActivity = - g_calculatorProvider.StartActivity(EVENT_NAME_APP_LAUNCH_BEGIN, nullptr, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_TELEMETRY)); - - isAppLaunchBeginLogged = true; - } - } - - void TraceLogger::LogAppLaunchComplete(/*Windows::ApplicationModel::Activation::ActivationKind activationKind, Windows::ApplicationModel::Activation::ApplicationExecutionState executionState*/) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - if ((m_appLaunchActivity != nullptr) && (!isAppLaunchEndLogged)) - { - m_appLaunchActivity.StopActivity(EVENT_NAME_APP_LAUNCH_END); - - isAppLaunchEndLogged = true; - } - - m_appLaunchActivity = nullptr; - } - - void TraceLogger::LogAppResumeComplete() - { - if (m_appLaunchActivity != nullptr) - { - m_appLaunchActivity.StopActivity(EVENT_NAME_APP_RESUME_END); - } - - m_appLaunchActivity = nullptr; - } - - void TraceLogger::LogDebug(wstring_view debugData) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"DebugData", debugData); - LogTelemetryEvent(EVENT_NAME_DEBUG, fields); - } - - void TraceLogger::LogOnAppLaunch(wstring_view previousExecutionState) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"PreviousExecutionState", previousExecutionState); - LogTelemetryEvent(EVENT_NAME_PREVIOUS_STATE_WINDOW_ON_CREATION, fields); - } - - void TraceLogger::LogAboutFlyoutOpened() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_ABOUT_FLYOUT_OPENED, fields); - } - - void TraceLogger::LogNavBarOpened() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_NAV_BAR_OPENED, fields); - } - - void TraceLogger::LogClearHistory() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_HISTORY_CLEAR, fields); - } - - void TraceLogger::LogHistoryFlyoutOpenBegin(unsigned int historyItemCount) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - // we want to record the event only when history item count is atleast 20 - if (historyItemCount >= 20) - { - LoggingFields fields{}; - fields.AddUInt32(L"HistoryItemCount", historyItemCount); - LogTelemetryEvent(EVENT_NAME_HISTORY_FLYOUT_OPEN_BEGIN, fields); - } - } - - void TraceLogger::LogHistoryFlyoutOpenEnd(int historyItemCount) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - if (historyItemCount >= 20) - { - LoggingFields fields{}; - fields.AddUInt32(L"HistoryItemCount", historyItemCount); - LogTelemetryEvent(EVENT_NAME_HISTORY_FLYOUT_OPEN_END, fields); - } - } - - void TraceLogger::LogHistoryBodyOpened() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_HISTORY_BODY_OPENED, fields); - } - - void TraceLogger::LogMemoryFlyoutOpenBegin(unsigned int memoryItemCount) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - // we want to record the event only when memory item count is atleast 4 - if (memoryItemCount >= 4) - { - LoggingFields fields{}; - fields.AddUInt32(L"MemoryItemCount", memoryItemCount); - LogTelemetryEvent(EVENT_NAME_MEMORY_FLYOUT_OPEN_BEGIN, fields); - } - } - - void TraceLogger::LogMemoryFlyoutOpenEnd(unsigned int memoryItemCount) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - if (memoryItemCount >= 4) - { - LoggingFields fields{}; - fields.AddUInt32(L"MemoryItemCount", memoryItemCount); - LogTelemetryEvent(EVENT_NAME_MEMORY_FLYOUT_OPEN_END, fields); - } - } - - void TraceLogger::LogMemoryBodyOpened() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_MEMORY_BODY_OPENED, fields); - } - - // If calculator is launched in any mode other than standard then this call will come which is not intended. But there is no way to avoid it. - // So don't use this function to analyze the count of mode change in session instead use CalculatorViewedInSession and ConverterViewedInSession to do that. - // Use of this function is to analyze perf of mode change. - void TraceLogger::LogModeChangeBegin(ViewMode fromMode, ViewMode toMode, int windowId) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - if (NavCategory::IsValidViewMode(fromMode) && NavCategory::IsValidViewMode(toMode)) - { - LoggingFields fields{}; - fields.AddString(L"FromMode", NavCategory::GetFriendlyName(fromMode)->Data()); - fields.AddString(L"ToMode", NavCategory::GetFriendlyName(toMode)->Data()); - fields.AddInt32(L"WindowId", windowId); - LogMeasureEvent(EVENT_NAME_MODE_CHANGE_BEGIN, fields); - } - } - - // comment: same as LogModeChangeBegin - void TraceLogger::LogModeChangeEnd(ViewMode toMode, int windowId) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - if (NavCategory::IsValidViewMode(toMode)) - { - LoggingFields fields{}; - fields.AddString(L"ToMode", NavCategory::GetFriendlyName(toMode)->Data()); - fields.AddInt32(L"WindowId", windowId); - LogMeasureEvent(EVENT_NAME_MODE_CHANGE_END, fields); - } - } - - void TraceLogger::LogHistoryItemLoadBegin() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_HISTORY_ITEM_LOAD_BEGIN, fields); - } - - void TraceLogger::LogHistoryItemLoadEnd(unsigned int historyTokenCount) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddUInt32(L"HistoryTokenCount", historyTokenCount); - LogTelemetryEvent(EVENT_NAME_HISTORY_ITEM_LOAD_END, fields); - } - - void TraceLogger::LogNewWindowCreationBegin(int windowId) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_NEW_WINDOW_CREATION_BEGIN, fields); - } - - void TraceLogger::LogNewWindowCreationEnd(int windowId) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_NEW_WINDOW_CREATION_END, fields); - } - - void TraceLogger::LogError(wstring_view errorString) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"ErrorString", errorString); - LogTelemetryEvent(EVENT_NAME_ERROR, fields); - } - - void TraceLogger::LogPrelaunchedAppActivatedByUser() - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_PRELAUNCHED_APP_ACTIVATED_BY_USER, fields); - } - - void TraceLogger::LogAppPrelaunchedBySystem() - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_APP_PRELAUNCHED_BY_SYSTEM, fields); - } - - void TraceLogger::LogMemoryClearAll(int windowId) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - auto iterMap = s_memoryMap.find(windowId); - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_MEMORY_CLEAR_ALL, fields); - - if (iterMap != s_memoryMap.end()) - { - iterMap->second.clear(); - } - } - - void - TraceLogger::LogMemoryUsed(int windowId, unsigned int slotPosition, bool isStandard, bool isScientific, bool isProgrammer, unsigned int memorySize) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - // Reader lock for the static resources - reader_writer_lock::scoped_lock_read lock(s_traceLoggerLock); - auto iterMap = s_memoryMap.find(windowId); - - if (slotPosition == 0) - { - LogSingleMemoryUsed(memorySize); - } - else - { - LogMultipleMemoryUsed(slotPosition, memorySize); - } - - if (iterMap != s_memoryMap.end()) - { - // if current mode is not equal to mode of memoryMap[slotPosition] then LogSharedMemoryUsed - if (isStandard && (iterMap->second[slotPosition] != L"Standard")) - { - LogSharedMemoryUsed(iterMap->second[slotPosition], L"Standard", memorySize); - } - else if (isScientific && (iterMap->second[slotPosition] != L"Scientific")) - { - LogSharedMemoryUsed(iterMap->second[slotPosition], L"Scientific", memorySize); - } - else if (isProgrammer && (iterMap->second[slotPosition] != L"Programmer")) - { - LogSharedMemoryUsed(iterMap->second[slotPosition], L"Programmer", memorySize); - } - } - } - - void TraceLogger::LogMultipleMemoryUsed(unsigned int slotPosition, unsigned int memorySize) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddUInt32(L"MemoryIndex", slotPosition); - fields.AddUInt32(L"MemoryListSize", memorySize); - LogTelemetryEvent(EVENT_NAME_MULTIPLE_MEMORY_USED, fields); - } - - void TraceLogger::LogSingleMemoryUsed(unsigned int memorySize) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddUInt32(L"MemoryListSize", memorySize); - LogTelemetryEvent(EVENT_NAME_SINGLE_MEMORY_USED, fields); - } - - void TraceLogger::LogInvalidPastedInputOccurred(wstring_view reason, ViewMode mode, int programmerNumberBase, int bitLengthType) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"Mode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"Reason", reason); - fields.AddString(L"ProgrammerNumberBase", GetProgrammerType(programmerNumberBase).c_str()); - fields.AddString(L"BitLengthType", GetProgrammerType(bitLengthType).c_str()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogTelemetryEvent(EVENT_NAME_INVALID_PASTED_INPUT_OCCURRED, fields); - } - - void TraceLogger::LogValidInputPasted(ViewMode mode) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"Mode", NavCategory::GetFriendlyName(mode)->Data()); - LogTelemetryEvent(EVENT_NAME_VALID_INPUT_PASTED, fields); - } - - void TraceLogger::LogStandardException(wstring_view functionName, const exception& e) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"FunctionName", functionName); - wstringstream exceptionMessage; - exceptionMessage << e.what(); - fields.AddString(L"ExceptionMessage", exceptionMessage.str()); - LogMeasureEvent(EVENT_NAME_EXCEPTION, fields); - } - - void TraceLogger::LogWinRTException(wstring_view functionName, hresult_error const& e) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"FunctionName", functionName); - fields.AddInt32(L"HRESULT", e.code()); - fields.AddString(L"ExceptionMessage", e.message()); - LogMeasureEvent(EVENT_NAME_EXCEPTION, fields); - } - - void TraceLogger::LogPlatformException(wstring_view functionName, Platform::Exception ^ e) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddString(L"FunctionName", functionName); - fields.AddInt32(L"HRESULT", e->HResult); - fields.AddString(L"ExceptionMessage", e->Message->Data()); - LogMeasureEvent(EVENT_NAME_EXCEPTION, fields); - } - - void TraceLogger::UpdateFunctionUsage(int funcIndex) - { - // Writer lock for the static resources - reader_writer_lock::scoped_lock lock(s_traceLoggerLock); - - if (GetIndex(funcIndex)) - { - // funcIndex is passed by reference and will be having the returned index - funcLog[funcIndex].count++; - } - } - - void TraceLogger::InitFunctionLogArray() - { - int i = -1; - for (int funcIndex = 0; funcIndex != maxFunctionSize; funcIndex++) - { - FunctionLogEnum func = safe_cast(funcIndex); - wstring functionName = func.ToString()->Data(); - if (functionName.compare(L"CalculatorApp.FunctionLogEnum") != 0) - { - findIndex[funcIndex] = ++i; - funcLog.push_back(FuncLog(functionName)); - } - } - // update the functionCount with total function count which we are tracking through tracelog. - functionCount = i; - } - - wstring TraceLogger::GetProgrammerType(int index) - { - if (index >= 0) - { - return s_programmerType[index]; - } - // return "N/A" - return s_programmerType[0]; - } - - bool TraceLogger::GetIndex(int& index) - { - if (findIndex[index] > 0) - { - index = findIndex[index]; - return true; - } - return false; - } - - void TraceLogger::UpdateWindowCount(size_t windowCount) - { - maxWindowCount = (maxWindowCount > windowCount) ? maxWindowCount : windowCount; - windowLaunchCount++; - } - - void TraceLogger::LogMaxWindowCount() - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddUInt32(L"WindowCount", (unsigned int)maxWindowCount); - LogTelemetryEvent(EVENT_NAME_MAX_WINDOW_COUNT, fields); - } - - void TraceLogger::LogWindowActivated() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_WINDOW_LAUNCHED_PROTOCOL, fields); - } - - void TraceLogger::LogWindowLaunched() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_WINDOW_LAUNCHED_TILESEARCH, fields); - } - - void TraceLogger::LogBitLengthButtonUsed(int windowId) - { - if (bitLengthButtonUsage.find(windowId) == bitLengthButtonUsage.end()) - { - bitLengthButtonUsage.insert(pair(windowId, 1)); - } - else - { - bitLengthButtonUsage[windowId]++; - } - if ((bitLengthButtonUsage[windowId] == 5) && !bitLengthButtonLoggedInSession) - { - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_BITLENGTH_BUTTON_USED, fields); - - bitLengthButtonLoggedInSession = true; - } - } - - void TraceLogger::LogRadixButtonUsed(int windowId) - { - if (radixButtonUsage.find(windowId) == radixButtonUsage.end()) - { - radixButtonUsage.insert(pair(windowId, 1)); - } - else - { - radixButtonUsage[windowId]++; - } - if ((radixButtonUsage[windowId] == 2) && !radixButtonLoggedInSession) - { - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_RADIX_BUTTON_USED, fields); - - radixButtonLoggedInSession = true; - } - } - - void TraceLogger::LogAngleButtonUsed(int windowId) - { - if (angleButtonUsage.find(windowId) == angleButtonUsage.end()) - { - angleButtonUsage.insert(pair(windowId, 1)); - } - else - { - angleButtonUsage[windowId]++; - } - if ((angleButtonUsage[windowId] == 2) && !angleButtonLoggedInSession) - { - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_ANGLE_BUTTONS_USED, fields); - - angleButtonLoggedInSession = true; - } - } - - void TraceLogger::LogFunctionUsage(int windowId) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - for (int i = 0; i < functionCount; i++) - { - // log only those functions which are used - if (funcLog[i].count > 0) - { - LoggingFields fields{}; - fields.AddString(L"FunctionName", funcLog[i].funcName.data()); - fields.AddUInt32(L"UsageCount", funcLog[i].count); - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_FUNCTION_USAGE, fields); - } - } - } - - void TraceLogger::LogHypButtonUsed(int windowId) - { - if (!isHypButtonLogged) - { - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_HYP_BUTTON_USED, fields); - - isHypButtonLogged = true; - } - } - - void TraceLogger::LogDateDifferenceModeUsed(int windowId) - { - if (!m_dateDiffUsageLoggedInSession) - { - LoggingFields fields{}; - fields.AddUInt32(L"WindowId", windowId); - LogTelemetryEvent(EVENT_NAME_DATE_DIFFERENCE_USED, fields); - - m_dateDiffUsageLoggedInSession = true; - } - } - - void TraceLogger::LogDateAddSubtractModeUsed(int windowId, bool isAddMode) - { - auto usageMap = isAddMode ? &m_dateAddModeUsage : &m_dateSubtractModeUsage; - auto isLoggedInSession = isAddMode ? &m_dateAddUsageLoggedInSession : &m_dateSubtractUsageLoggedInSession; - - if (usageMap->find(windowId) == usageMap->end()) - { - usageMap->insert(pair(windowId, 1)); - } - else - { - (*usageMap)[windowId]++; - } - - // Ignore first 3 calls during the initialization of the combo box selected items for Add mode - int firstChangeEventCount = isAddMode ? 4 : 1; - - if (((*usageMap)[windowId] == firstChangeEventCount) && (!(*isLoggedInSession))) - { - LoggingFields fields{}; - fields.AddString(L"AddSubtractMode", isAddMode ? L"Add" : L"Subtract"); - LogTelemetryEvent(EVENT_NAME_DATE_ADD_SUBTRACT_USED, fields); - - *isLoggedInSession = true; - } - } - - void TraceLogger::LogDateClippedTimeDifferenceFound(Calendar const& today, DateTime const& clippedTime) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - auto calendarSystem = today.GetCalendarSystem(); - auto clock = today.GetClock(); - DateTimeFormatter dtFormatter{ L"longdate shorttime", { L"en-US" }, GlobalizationPreferences::HomeGeographicRegion(), calendarSystem, clock }; - - LoggingFields fields{}; - fields.AddString(L"ResolvedCalendarLanguage", today.ResolvedLanguage()); - fields.AddString(L"Timezone", today.GetTimeZone()); - fields.AddString(L"CalendarSystem", calendarSystem); - fields.AddString(L"Clock", clock); - fields.AddBoolean(L"IsDaylightSavingTime", today.IsDaylightSavingTime()); - fields.AddString(L"TodayDate", dtFormatter.Format(today.GetDateTime())); - fields.AddString(L"ClippedDate", dtFormatter.Format(clippedTime)); - LogTelemetryEvent(EVENT_NAME_DATE_DIFFERENCE_FOUND, fields); - } - - void TraceLogger::LogUserRequestedRefreshFailed() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(L"UserRequestedRefreshFailed", fields); - } - - void TraceLogger::LogConversionResult(wstring_view fromValue, wstring_view fromUnit, wstring_view toValue, wstring_view toUnit) const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - wstring behaviorString{}; - NetworkAccessBehavior behavior = NetworkManager::GetNetworkAccessBehavior(); - switch (behavior) - { - case NetworkAccessBehavior::Offline: - behaviorString = L"Offline"; - break; - - case NetworkAccessBehavior::OptIn: - behaviorString = L"Metered"; - break; - - case NetworkAccessBehavior::Normal: - default: - behaviorString = L"Online"; - break; - } - - LoggingFields fields{}; - fields.AddString(L"NetworkAccess", behaviorString); - fields.AddString(L"FromValue", fromValue); - fields.AddString(L"FromUnit", fromUnit); - fields.AddString(L"ToValue", toValue); - fields.AddString(L"ToUnit", toUnit); - LogTelemetryEvent(L"CurrencyConverterInputReceived", fields); - } - - void TraceLogger::LogViewClosingTelemetry(int windowId) - { - LogFunctionUsage(windowId); - LogMaxWindowCount(); - } - - void TraceLogger::LogCoreWindowWasNull() const - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - LogTelemetryEvent(EVENT_NAME_CORE_WINDOW_WAS_NULL, fields); - } -} diff --git a/src/CalcViewModel/Common/TraceLogger.h b/src/CalcViewModel/Common/TraceLogger.h deleted file mode 100644 index 870cddf8..00000000 --- a/src/CalcViewModel/Common/TraceLogger.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/Command.h" -#include "TraceActivity.h" -#include "NavCategory.h" - -static const int maxFunctionSize = (int)CalculationManager::Command::CommandBINEDITEND; - -// A trace logging provider can only be instantiated and registered once per module. -// This class implements a singleton model ensure that only one instance is created. -namespace CalculatorApp -{ - struct FuncLog - { - public: - int count; - std::wstring funcName; - FuncLog() - { - count = 0; - } - FuncLog(std::wstring fName) - { - funcName = fName; - count = 0; - } - }; - - class TraceLogger - { - public: - TraceLogger(_In_ TraceLogger const&) = delete; - TraceLogger const& operator=(_In_ TraceLogger const&) = delete; - ~TraceLogger(); - static TraceLogger& GetInstance(); - bool GetTraceLoggingProviderEnabled() const; - - void LogAppLaunchStart(); - void LogAppLaunchComplete(); - void LogAppResumeComplete(); - void LogOnAppLaunch(std::wstring_view previousExecutionState) const; - void LogMemoryClearAll(int); - void LogBitFlipPaneClicked() const; - void LogBitFlipUsed() const; - void LogHistoryBodyOpened() const; - void LogHistoryItemLoadBegin() const; - void LogHistoryItemLoadEnd(unsigned int) const; - void LogHistoryFlyoutOpenBegin(unsigned int) const; - void LogHistoryFlyoutOpenEnd(int) const; - void LogCalculatorModeViewed(CalculatorApp::Common::ViewMode, int); - void LogDateCalculatorModeViewed(CalculatorApp::Common::ViewMode, int); - void LogConverterModeViewed(CalculatorApp::Common::ViewMode, int); - void LogModeChangeBegin(CalculatorApp::Common::ViewMode, CalculatorApp::Common::ViewMode, int); - void LogModeChangeEnd(CalculatorApp::Common::ViewMode, int) const; - void LogClearHistory() const; - void InsertIntoMemoryMap(int, bool, bool, bool); - void UpdateMemoryMap(int, int, bool, bool, bool); - void DeleteFromMemoryMap(int, int); - void LogMemoryUsed(int, unsigned int, bool, bool, bool, unsigned int) const; - void LogMultipleMemoryUsed(unsigned int, unsigned int) const; - void LogSingleMemoryUsed(unsigned int) const; - void LogSharedMemoryUsed(std::wstring_view, std::wstring_view, unsigned int) const; - void LogMemoryBodyOpened() const; - void LogMemoryFlyoutOpenBegin(unsigned int) const; - void LogDebug(std::wstring_view debugData); - void LogMemoryFlyoutOpenEnd(unsigned int) const; - void LogInvalidPastedInputOccurred(std::wstring_view reason, CalculatorApp::Common::ViewMode mode, int ProgrammerNumberBase, int bitLengthType); - void LogValidInputPasted(CalculatorApp::Common::ViewMode mode) const; - void UpdateFunctionUsage(int func); - void LogFunctionUsage(int); - void InitFunctionLogArray(); - void LogBitLengthButtonUsed(int windowId); - void LogRadixButtonUsed(int windowId); - void LogAngleButtonUsed(int windowId); - void LogHypButtonUsed(int windowId); - void LogNewWindowCreationBegin(int windowId); - void LogNewWindowCreationEnd(int windowId); - void LogError(std::wstring_view errorString); - void LogPrelaunchedAppActivatedByUser(); - void LogAppPrelaunchedBySystem(); - void UpdateWindowCount(size_t windowCount); - bool UpdateWindowIdLog(int windowId); - void LogMaxWindowCount(); - void LogWindowActivated() const; - void LogWindowLaunched() const; - void LogUserRequestedRefreshFailed() const; - void LogConversionResult(std::wstring_view fromValue, std::wstring_view fromUnit, std::wstring_view toValue, std::wstring_view toUnit) const; - void LogAboutFlyoutOpened() const; - void LogNavBarOpened() const; - void LogViewClosingTelemetry(int); - void LogCoreWindowWasNull() const; - - // Trace methods for Date Calculator usage - void LogDateDifferenceModeUsed(int windowId); - void LogDateAddSubtractModeUsed(int windowId, bool isAddMode); - void - LogDateClippedTimeDifferenceFound(winrt::Windows::Globalization::Calendar const& today, winrt::Windows::Foundation::DateTime const& clippedTime) const; - - void LogStandardException(std::wstring_view functionName, _In_ const std::exception& e) const; - void LogWinRTException(std::wstring_view functionName, _In_ winrt::hresult_error const& e) const; - void LogPlatformException(std::wstring_view functionName, _In_ Platform::Exception ^ e) const; - - private: - // Create an instance of TraceLogger - TraceLogger(); - - // Any new Log method should - // a) decide the level of logging. This will help us in limiting recording of events only up to a certain level. See this link for guidance - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363742(v=vs.85).aspx We're using Verbose level for events that are called frequently and - // needed only for debugging or capturing perf for specific scenarios b) should decide whether or not to log to telemetry and pass - // TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY) accordingly c) Should accept a variable number of additional data arguments if needed - void LogTelemetryEvent(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - void LogMeasureEvent(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - void LogCriticalDataEvent(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - void LogPerformanceEvent(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - void LogInfoEvent(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - - std::unique_ptr CreateTraceActivity(std::wstring_view activityName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - - winrt::Windows::Foundation::Diagnostics::LoggingChannel g_calculatorProvider; - - bool isSizeChangeLogged = false; - bool isHideIfShownLogged = false; - bool isSizeChangedFirstTime = true; // to track the first size changed event which is fired on the launch of app - bool isAutoConversionBeginLoggedInSession = false; - bool isAutoConversionEndLoggedInSession = false; - bool angleButtonLoggedInSession = false; - bool radixButtonLoggedInSession = false; - bool bitLengthButtonLoggedInSession = false; - GUID sessionGuid; - CalculatorApp::Common::ViewMode currentMode = CalculatorApp::Common::ViewMode::None; - std::vector funcLog; - int functionCount = 0; - bool isHypButtonLogged = false; - bool isAngleButtonInitialized = false; - unsigned int findIndex[maxFunctionSize] = { 0 }; - bool GetIndex(int& index); - std::wstring GetProgrammerType(int index); - size_t maxWindowCount = 0; - bool isAppLaunchBeginLogged = false; - bool isAppLaunchEndLogged = false; - std::map bitLengthButtonUsage; - std::map angleButtonUsage; - std::map radixButtonUsage; - std::map windowIdLog; - - // Private variables for Date Calculator usage - bool m_dateDiffUsageLoggedInSession = false; - bool m_dateAddUsageLoggedInSession = false; - bool m_dateSubtractUsageLoggedInSession = false; - std::map m_dateAddModeUsage; - std::map m_dateSubtractModeUsage; - - size_t windowLaunchCount = 0; - - winrt::Windows::Foundation::Diagnostics::LoggingActivity m_appLaunchActivity; - }; -} diff --git a/src/CalcViewModel/Common/Utils.cpp b/src/CalcViewModel/Common/Utils.cpp deleted file mode 100644 index 8ad60816..00000000 --- a/src/CalcViewModel/Common/Utils.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// -// Utils.cpp -// - -#include "pch.h" -#include "Utils.h" -#include "Common/AppResourceProvider.h" -#include "Common/ExpressionCommandSerializer.h" -#include "Common/ExpressionCommandDeserializer.h" -#include "ViewState.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace concurrency; -using namespace Platform; -using namespace std; -using namespace Utils; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::Storage::Streams; -using namespace Windows::UI::Core; -using namespace Windows::UI::ViewManagement; -using namespace Windows::UI::Xaml; -using namespace Windows::Foundation; -using namespace Windows::Storage; - -void Utils::IFTPlatformException(HRESULT hr) -{ - if (FAILED(hr)) - { - Platform::Exception ^ exception = ref new Platform::Exception(hr); - throw(exception); - } -} - -String ^ Utils::GetStringValue(String ^ input) -{ - // Remove first and last " characters - if (input->Length() >= 3) - { - wstring out(input->Begin() + 1, input->End() - 1); - return ref new String(out.c_str()); - } - return input; -} - -double Utils::GetDoubleFromWstring(wstring input) -{ - wchar_t unWantedChars[] = { L' ', L',', 8234, 8235, 8236, 8237 }; - wstring ws = RemoveUnwantedCharsFromWstring(input, unWantedChars, 6); - string inputString(ws.begin(), ws.end()); - return ::atof(inputString.c_str()); -} - -// Returns windowId for the current view -int Utils::GetWindowId() -{ - int windowId = -1; - - auto window = CoreWindow::GetForCurrentThread(); - if (window != nullptr) - { - windowId = ApplicationView::GetApplicationViewIdForWindow(window); - } - - return windowId; -} - -void Utils::RunOnUIThreadNonblocking(std::function&& function, _In_ CoreDispatcher ^ currentDispatcher) -{ - if (currentDispatcher != nullptr) - { - auto task = create_task(currentDispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([function]() { function(); }))); - } -} - -// Returns if the last character of a wstring is the target wchar_t -bool Utils::IsLastCharacterTarget(_In_ wstring const& input, _In_ wchar_t target) -{ - return !input.empty() && input.back() == target; -} - -// Return wstring after removing characters specified by unwantedChars array -wstring Utils::RemoveUnwantedCharsFromWstring(wstring input, wchar_t* unwantedChars, unsigned int size) -{ - for (unsigned int i = 0; i < size; ++i) - { - input.erase(std::remove(input.begin(), input.end(), unwantedChars[i]), input.end()); - } - return input; -} - -void Utils::SerializeCommandsAndTokens( - _In_ shared_ptr>> const& tokens, - _In_ shared_ptr>> const& commands, - DataWriter ^ writer) -{ - unsigned int commandsSize; - IFTPlatformException(commands->GetSize(&commandsSize)); - - // Save the size of the commands vector - writer->WriteUInt32(commandsSize); - - SerializeCommandVisitor cmdVisitor(writer); - for (unsigned int i = 0; i < commandsSize; ++i) - { - shared_ptr exprCmd; - IFTPlatformException(commands->GetAt(i, &exprCmd)); - - CalculationManager::CommandType commandType = exprCmd->GetCommandType(); - writer->WriteInt32(static_cast(commandType)); - exprCmd->Accept(cmdVisitor); - } - - unsigned int tokensSize; - IFTPlatformException(tokens->GetSize(&tokensSize)); - writer->WriteUInt32(tokensSize); - - for (unsigned int i = 0; i < tokensSize; ++i) - { - pair eachToken; - IFTPlatformException(tokens->GetAt(i, &eachToken)); - - auto stringData = ref new Platform::String(eachToken.first.c_str()); - auto intData = eachToken.second; - writer->WriteUInt32(writer->MeasureString(stringData)); - writer->WriteString(stringData); - writer->WriteInt32(intData); - } -} - -const shared_ptr>> Utils::DeserializeCommands(DataReader ^ reader) -{ - shared_ptr>> commandVector = make_shared>>(); - auto commandVectorSize = reader->ReadUInt32(); - - CommandDeserializer cmdDeserializer(reader); - for (unsigned int i = 0; i < commandVectorSize; ++i) - { - auto commandTypeInt = reader->ReadInt32(); - CalculationManager::CommandType commandType = static_cast(commandTypeInt); - shared_ptr exprCmd = cmdDeserializer.Deserialize(commandType); - commandVector->Append(exprCmd); - } - - return commandVector; -} - -const shared_ptr>> Utils::DeserializeTokens(DataReader ^ reader) -{ - shared_ptr>> tokenVector = make_shared>>(); - auto tokensSize = reader->ReadUInt32(); - - for (unsigned int i = 0; i < tokensSize; ++i) - { - pair eachToken; - auto stringDataLen = reader->ReadUInt32(); - auto stringData = reader->ReadString(stringDataLen); - auto intData = reader->ReadInt32(); - eachToken.first = stringData->Data(); - eachToken.second = intData; - tokenVector->Append(eachToken); - } - - return tokenVector; -} - -DateTime Utils::GetUniversalSystemTime() -{ - SYSTEMTIME sysTime = {}; - GetSystemTime(&sysTime); - - FILETIME sysTimeAsFileTime = {}; - SystemTimeToFileTime(&sysTime, &sysTimeAsFileTime); - - ULARGE_INTEGER ularge; - ularge.HighPart = sysTimeAsFileTime.dwHighDateTime; - ularge.LowPart = sysTimeAsFileTime.dwLowDateTime; - - DateTime result; - result.UniversalTime = ularge.QuadPart; - return result; -} - -bool Utils::IsDateTimeOlderThan(DateTime dateTime, const long long duration) -{ - DateTime now = Utils::GetUniversalSystemTime(); - return dateTime.UniversalTime + duration < now.UniversalTime; -} - -task Utils::WriteFileToFolder(IStorageFolder ^ folder, String ^ fileName, String ^ contents, CreationCollisionOption collisionOption) -{ - if (folder == nullptr) - { - co_return; - } - - StorageFile ^ file = co_await folder->CreateFileAsync(fileName, collisionOption); - if (file == nullptr) - { - co_return; - } - - co_await FileIO::WriteTextAsync(file, contents); -} - -task Utils::ReadFileFromFolder(IStorageFolder ^ folder, String ^ fileName) -{ - if (folder == nullptr) - { - co_return nullptr; - } - - StorageFile ^ file = co_await folder->GetFileAsync(fileName); - if (file == nullptr) - { - co_return nullptr; - } - - String ^ contents = co_await FileIO::ReadTextAsync(file); - co_return contents; -} diff --git a/src/CalcViewModel/Common/Utils.h b/src/CalcViewModel/Common/Utils.h deleted file mode 100644 index 45eeefe2..00000000 --- a/src/CalcViewModel/Common/Utils.h +++ /dev/null @@ -1,699 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/CalculatorVector.h" -#include "CalcManager/ExpressionCommandInterface.h" -#include "DelegateCommand.h" - -// Utility macros to make Models easier to write -// generates a member variable called m_ -#define PROPERTY_R(t, n) \ - property t n \ - { \ - t get() \ - { \ - return m_##n; \ - } \ - \ - private: \ - void set(t value) \ - { \ - m_##n = value; \ - } \ - } \ - \ -private: \ - t m_##n; \ - \ -public: - -#define PROPERTY_RW(t, n) \ - property t n \ - { \ - t get() \ - { \ - return m_##n; \ - } \ - void set(t value) \ - { \ - m_##n = value; \ - } \ - } \ - \ -private: \ - t m_##n; \ - \ -public: - -#define OBSERVABLE_PROPERTY_R(t, n) \ - property t n \ - { \ - t get() \ - { \ - return m_##n; \ - } \ - \ - private: \ - void set(t value) \ - { \ - if (m_##n != value) \ - { \ - m_##n = value; \ - RaisePropertyChanged(L#n); \ - } \ - } \ - } \ - \ -private: \ - t m_##n; \ - \ -public: - -#define OBSERVABLE_PROPERTY_RW(t, n) \ - property t n \ - { \ - t get() \ - { \ - return m_##n; \ - } \ - void set(t value) \ - { \ - if (m_##n != value) \ - { \ - m_##n = value; \ - RaisePropertyChanged(L#n); \ - } \ - } \ - } \ - \ -private: \ - t m_##n; \ - \ -public: - -#define OBSERVABLE_NAMED_PROPERTY_R(t, n) \ - OBSERVABLE_PROPERTY_R(t, n) \ - internal: \ - static property Platform::String ^ n##PropertyName \ - { \ - Platform::String ^ get() { return Platform::StringReference(L#n); } \ - } \ - \ -public: - -#define OBSERVABLE_NAMED_PROPERTY_RW(t, n) \ - OBSERVABLE_PROPERTY_RW(t, n) \ - internal: \ - static property Platform::String ^ n##PropertyName \ - { \ - Platform::String ^ get() { return Platform::StringReference(L#n); } \ - } \ - \ -public: - -#define OBSERVABLE_PROPERTY_FIELD(n) m_##n - -// This variant of the observable object is for objects that don't want to react to property changes -#ifndef UNIT_TESTS -#define OBSERVABLE_OBJECT() \ - virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ - internal: \ - void RaisePropertyChanged(Platform::String ^ p) \ - { \ - PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); \ - } \ - \ -public: -#else -#define OBSERVABLE_OBJECT() \ - virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ - internal: \ - void RaisePropertyChanged(Platform::String ^ p) \ - { \ - } \ - \ -public: -#endif - -// The callback specified in the macro is a method in the class that will be called every time the object changes -// the callback is supposed to be have a single parameter of type Platform::String^ -#ifndef UNIT_TESTS -#define OBSERVABLE_OBJECT_CALLBACK(c) \ - virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ - internal: \ - void RaisePropertyChanged(Platform::String ^ p) \ - { \ - PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); \ - c(p); \ - } \ - \ -public: -#else -#define OBSERVABLE_OBJECT_CALLBACK(c) \ - virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ - internal: \ - void RaisePropertyChanged(Platform::String ^ p) \ - { \ - c(p); \ - } \ - \ -public: -#endif - -// The variable member generated by this macro should not be used in the class code, use the -// property getter instead. -#define COMMAND_FOR_METHOD(p, m) \ - property Windows::UI::Xaml::Input::ICommand^ p {\ - Windows::UI::Xaml::Input::ICommand^ get() {\ - if (!donotuse_##p) {\ - donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\ - } return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; \ - \ -public: - -#define DEPENDENCY_PROPERTY_DECLARATION(t, n) \ - property t n \ - { \ - t get() \ - { \ - return safe_cast(GetValue(s_##n##Property)); \ - } \ - void set(t value) \ - { \ - SetValue(s_##n##Property, value); \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##n##Property; \ - \ -public: - -// Utilities for DependencyProperties -namespace Utils -{ - namespace Details - { - template - struct IsRefClass - { - static const bool value = __is_ref_class(T); - }; - - template - struct RemoveHat - { - typedef T type; - }; - - template - struct RemoveHat - { - typedef T type; - }; - - template - typename std::enable_if::value, T ^>::type MakeDefault() - { - return nullptr; - } - - template - typename std::enable_if::value, T>::type MakeDefault() - { - return T(); - } - - // There's a bug in Xaml in which custom enums are not recognized by the property system/binding - // therefore this template will determine that for enums the type to use to register the - // DependencyProperty is to be Object, for everything else it will use the type - // NOTE: If we are to find more types in which this is broken this template - // will be specialized for those types to return Object - template - struct TypeToUseForDependencyProperty - { - typedef typename std::conditional::value, Platform::Object, T>::type type; - }; - } - - const wchar_t LRE = 0x202a; // Left-to-Right Embedding - const wchar_t PDF = 0x202c; // Pop Directional Formatting - const wchar_t LRO = 0x202d; // Left-to-Right Override - - // Regular DependencyProperty - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty( - _In_ const wchar_t* const name, - _In_ Windows::UI::Xaml::PropertyMetadata^ metadata) - { - typedef typename Details::RemoveHat::type OwnerType; - typedef typename Details::RemoveHat::type ThisPropertyType; - typedef typename Details::TypeToUseForDependencyProperty::type ThisDependencyPropertyType; - - static_assert(Details::IsRefClass::value, "The owner of a DependencyProperty must be a ref class"); - - return Windows::UI::Xaml::DependencyProperty::Register( - Platform::StringReference(name), - ThisDependencyPropertyType::typeid, // Work around bugs in Xaml by using the filtered type - OwnerType::typeid, - metadata); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name) - { - typedef typename Details::RemoveHat::type ThisPropertyType; - - return RegisterDependencyProperty( - name, - ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault())); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name, TType defaultValue) - { - return RegisterDependencyProperty( - name, - ref new Windows::UI::Xaml::PropertyMetadata(defaultValue)); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback( - _In_ wchar_t const * const name, - TCallback callback) - { - typedef typename Details::RemoveHat::type ThisPropertyType; - return RegisterDependencyProperty( - name, - ref new Windows::UI::Xaml::PropertyMetadata( - Details::MakeDefault(), - ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback( - _In_ wchar_t const * const name, - TType defaultValue, - TCallback callback) - { - typedef typename Details::RemoveHat::type ThisPropertyType; - return RegisterDependencyProperty( - name, - ref new Windows::UI::Xaml::PropertyMetadata( - defaultValue, - ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); - } - - // Attached DependencyProperty - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached( - _In_ const wchar_t* const name, - _In_ Windows::UI::Xaml::PropertyMetadata^ metadata) - { - typedef typename Details::RemoveHat::type OwnerType; - typedef typename Details::RemoveHat::type ThisPropertyType; - typedef typename Details::TypeToUseForDependencyProperty::type ThisDependencyPropertyType; - - static_assert(Details::IsRefClass::value, "The owner of a DependencyProperty must be a ref class"); - - return Windows::UI::Xaml::DependencyProperty::RegisterAttached( - Platform::StringReference(name), - ThisDependencyPropertyType::typeid, // Work around bugs in Xaml by using the filtered type - OwnerType::typeid, - metadata); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name) - { - typedef typename Details::RemoveHat::type ThisPropertyType; - return RegisterDependencyPropertyAttached( - name, - ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault())); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name, TType defaultValue) - { - return RegisterDependencyPropertyAttached( - name, - ref new Windows::UI::Xaml::PropertyMetadata(defaultValue)); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback( - _In_ wchar_t const * const name, - TCallback callback) - { - typedef typename Details::RemoveHat::type ThisPropertyType; - return RegisterDependencyPropertyAttached( - name, - ref new Windows::UI::Xaml::PropertyMetadata( - Details::MakeDefault(), - ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); - } - - template - Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback( - _In_ wchar_t const * const name, - TType defaultValue, - TCallback callback) - { - typedef typename Details::RemoveHat::type ThisPropertyType; - return RegisterDependencyPropertyAttached( - name, - ref new Windows::UI::Xaml::PropertyMetadata( - defaultValue, - ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); - } - - template - void Swap(T *ref1, T *ref2) - { - T temp = *ref1; - *ref1 = *ref2; - *ref2 = temp; - } - - void IFTPlatformException(HRESULT hr); - Platform::String ^ GetStringValue(Platform::String ^ input); - bool IsLastCharacterTarget(std::wstring const& input, wchar_t target); - std::wstring RemoveUnwantedCharsFromWstring(std::wstring inputString, wchar_t* unwantedChars, unsigned int size); - double GetDoubleFromWstring(std::wstring input); - int GetWindowId(); - void RunOnUIThreadNonblocking(std::function&& function, _In_ Windows::UI::Core::CoreDispatcher ^ currentDispatcher); - void SerializeCommandsAndTokens( - _In_ std::shared_ptr>> const& tokens, - _In_ std::shared_ptr>> const& commands, - Windows::Storage::Streams::DataWriter ^ writer); - - const std::shared_ptr>> DeserializeCommands(Windows::Storage::Streams::DataReader ^ reader); - const std::shared_ptr>> DeserializeTokens(Windows::Storage::Streams::DataReader ^ reader); - - Windows::Foundation::DateTime GetUniversalSystemTime(); - bool IsDateTimeOlderThan(Windows::Foundation::DateTime dateTime, const long long duration); - - 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); -} - -// This goes into the header to define the property, in the public: section of the class -#define DEPENDENCY_PROPERTY_OWNER(owner) \ -private: \ - typedef owner DependencyPropertiesOwner; \ - \ -public: - -// Normal DependencyProperty -#define DEPENDENCY_PROPERTY(type, name) \ - property type name \ - { \ - type get() \ - { \ - return safe_cast(GetValue(s_##name##Property)); \ - } \ - void set(type value) \ - { \ - SetValue(s_##name##Property, value); \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyProperty(L#name); \ - } \ - \ -public: - -#define DEPENDENCY_PROPERTY_WITH_DEFAULT(type, name, defaultValue) \ - property type name \ - { \ - type get() \ - { \ - return safe_cast(GetValue(s_##name##Property)); \ - } \ - void set(type value) \ - { \ - SetValue(s_##name##Property, value); \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyProperty(L#name, defaultValue); \ - } \ - \ -public: - -#define DEPENDENCY_PROPERTY_WITH_CALLBACK(type, name) \ - property type name \ - { \ - type get() \ - { \ - return safe_cast(GetValue(s_##name##Property)); \ - } \ - void set(type value) \ - { \ - SetValue(s_##name##Property, value); \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyPropertyWithCallback(L#name, &On##name##PropertyChangedImpl); \ - } \ - static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ - { \ - auto self = safe_cast(sender); \ - self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \ - } \ - \ -public: - -#define DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \ - property type name \ - { \ - type get() \ - { \ - return safe_cast(GetValue(s_##name##Property)); \ - } \ - void set(type value) \ - { \ - SetValue(s_##name##Property, value); \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyPropertyWithCallback(L#name, defaultValue, &On##name##PropertyChangedImpl); \ - } \ - static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ - { \ - auto self = safe_cast(sender); \ - self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \ - } \ - \ -public: - -// Attached DependencyProperty -#define DEPENDENCY_PROPERTY_ATTACHED(type, name) \ - static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ - { \ - return safe_cast(target->GetValue(s_##name##Property)); \ - } \ - static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ - { \ - target->SetValue(s_##name##Property, value); \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyPropertyAttached(L#name); \ - } \ - \ -public: - -#define DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT(type, name, defaultValue) \ - static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ - { \ - return safe_cast(target->GetValue(s_##name##Property)); \ - } \ - static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ - { \ - target->SetValue(s_##name##Property, value); \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyPropertyAttached(L#name, defaultValue); \ - } \ - \ -public: - -#define DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(type, name) \ - static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ - { \ - return safe_cast(target->GetValue(s_##name##Property)); \ - } \ - static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ - { \ - target->SetValue(s_##name##Property, value); \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyPropertyAttachedWithCallback(L#name, &On##name##PropertyChangedImpl); \ - } \ - static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ - { \ - On##name##PropertyChanged(sender, safe_cast(args->OldValue), safe_cast(args->NewValue)); \ - } \ - \ -public: - -#define DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \ - static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ - { \ - return safe_cast(target->GetValue(s_##name##Property)); \ - } \ - static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ - { \ - target->SetValue(s_##name##Property, value); \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ - \ -public: \ - static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ - { \ - Windows::UI::Xaml::DependencyProperty ^ get() { \ - assert(s_##name##Property); \ - return s_##name##Property; \ - } \ - } \ - \ -private: \ - static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ - { \ - return Utils::RegisterDependencyPropertyAttachedWithCallback(L#name, defaultValue, &On##name##PropertyChangedImpl); \ - } \ - static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ - { \ - On##name##PropertyChanged(sender, safe_cast(args->OldValue), safe_cast(args->NewValue)); \ - } \ - \ -public: - -// This goes into the cpp to initialize the static variable -#define DEPENDENCY_PROPERTY_INITIALIZATION(owner, name) Windows::UI::Xaml::DependencyProperty ^ owner::s_##name##Property = owner::Initialize##name##Property(); - -namespace CalculatorApp -{ - template - T from_cx(Platform::Object ^ from) - { - T to{ nullptr }; - - winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(to)))); - - return to; - } -} diff --git a/src/CalcViewModel/Common/ValidatingConverters.h b/src/CalcViewModel/Common/ValidatingConverters.h deleted file mode 100644 index bc168502..00000000 --- a/src/CalcViewModel/Common/ValidatingConverters.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace Common - { - public - ref class ValidSelectedItemConverter sealed : public Windows::UI::Xaml::Data::IValueConverter - { - public: - ValidSelectedItemConverter() - { - } - - private: - virtual Platform::Object - ^ Convert( - Platform::Object ^ value, - Windows::UI::Xaml::Interop::TypeName /*targetType*/, - Platform::Object ^ /*parameter*/, - Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert - { - // Pass through as we don't want to change the value from the source - return value; - } - - virtual Platform::Object - ^ ConvertBack( - Platform::Object ^ value, - Windows::UI::Xaml::Interop::TypeName /*targetType*/, - Platform::Object ^ /*parameter*/, - Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack - { - if (value) - { - return value; - } - // Stop the binding if the object is nullptr - return Windows::UI::Xaml::DependencyProperty::UnsetValue; - } - }; - - public - ref class ValidSelectedIndexConverter sealed : public Windows::UI::Xaml::Data::IValueConverter - { - public: - ValidSelectedIndexConverter() - { - } - - private: - virtual Platform::Object - ^ Convert( - Platform::Object ^ value, - Windows::UI::Xaml::Interop::TypeName /*targetType*/, - Platform::Object ^ /*parameter*/, - Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert - { - // Pass through as we don't want to change the value from the source - return value; - } - - virtual Platform::Object - ^ ConvertBack( - Platform::Object ^ value, - Windows::UI::Xaml::Interop::TypeName /*targetType*/, - Platform::Object ^ /*parameter*/, - Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack - { - // The value to be valid has to be a boxed int32 value - // extract that value and ensure it is valid, ie >= 0 - if (value) - { - auto box = dynamic_cast(value); - if (box && box->Type == Windows::Foundation::PropertyType::Int32) - { - int index = box->GetInt32(); - if (index >= 0) - { - return value; - } - } - } - // The value is not valid therefore stop the binding right here - return Windows::UI::Xaml::DependencyProperty::UnsetValue; - } - }; - } -} diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp deleted file mode 100644 index b2c68dcf..00000000 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp +++ /dev/null @@ -1,760 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "CurrencyDataLoader.h" -#include "Common/AppResourceProvider.h" -#include "Common/LocalizationStringUtil.h" -#include "Common/LocalizationService.h" -#include "Common/LocalizationSettings.h" -#include "Common/TraceLogger.h" -#include "UnitConverterDataConstants.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::LocalizationServiceProperties; -using namespace CalculatorApp::DataLoaders; -using namespace CalculatorApp::ViewModel; -using namespace CalculatorApp::ViewModel::CurrencyDataLoaderConstants; -using namespace concurrency; -using namespace Platform; -using namespace std; -using namespace UnitConversionManager; -using namespace Windows::ApplicationModel::Resources::Core; -using namespace Windows::Data::Json; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::Globalization::DateTimeFormatting; -using namespace Windows::Globalization::NumberFormatting; -using namespace Windows::Storage; -using namespace Windows::System::UserProfile; -using namespace Windows::UI::Core; -using namespace Windows::Web::Http; - -static constexpr auto CURRENCY_UNIT_FROM_KEY = L"CURRENCY_UNIT_FROM_KEY"; -static constexpr auto CURRENCY_UNIT_TO_KEY = L"CURRENCY_UNIT_TO_KEY"; - -// Calculate number of 100-nanosecond intervals-per-day -// (1 interval/100 nanosecond)(100 nanosecond/1e-7 s)(60 s/1 min)(60 min/1 hr)(24 hr/1 day) = (interval/day) -static constexpr long long DAY_DURATION = 1LL * 60 * 60 * 24 * 10000000; -static constexpr long long WEEK_DURATION = DAY_DURATION * 7; - -static constexpr int FORMATTER_DIGIT_COUNT = 4; - -static constexpr auto CACHE_TIMESTAMP_KEY = L"CURRENCY_CONVERTER_TIMESTAMP"; -static constexpr auto CACHE_LANGCODE_KEY = L"CURRENCY_CONVERTER_LANGCODE"; -static constexpr auto CACHE_DELIMITER = L"%"; - -static constexpr auto STATIC_DATA_FILENAME = L"CURRENCY_CONVERTER_STATIC_DATA.txt"; -static constexpr array STATIC_DATA_PROPERTIES = { wstring_view{ L"CountryCode", 11 }, - wstring_view{ L"CountryName", 11 }, - wstring_view{ L"CurrencyCode", 12 }, - wstring_view{ L"CurrencyName", 12 }, - wstring_view{ L"CurrencySymbol", 14 } }; - -static constexpr auto ALL_RATIOS_DATA_FILENAME = L"CURRENCY_CONVERTER_ALL_RATIOS_DATA.txt"; -static constexpr auto RATIO_KEY = L"Rt"; -static constexpr auto CURRENCY_CODE_KEY = L"An"; -static constexpr array ALL_RATIOS_DATA_PROPERTIES = { wstring_view{ RATIO_KEY, 2 }, wstring_view{ CURRENCY_CODE_KEY, 2 } }; - -static constexpr auto DEFAULT_FROM_TO_CURRENCY_FILE_URI = L"ms-appx:///DataLoaders/DefaultFromToCurrency.json"; -static constexpr auto FROM_KEY = L"from"; -static constexpr auto TO_KEY = L"to"; - -// Fallback default values. -static constexpr auto DEFAULT_FROM_CURRENCY = DefaultCurrencyCode.data(); -static constexpr auto DEFAULT_TO_CURRENCY = L"EUR"; - -namespace CalculatorApp -{ - namespace ViewModel - { - namespace UnitConverterResourceKeys - { - StringReference CurrencyUnitFromKey(CURRENCY_UNIT_FROM_KEY); - StringReference CurrencyUnitToKey(CURRENCY_UNIT_TO_KEY); - } - - namespace CurrencyDataLoaderConstants - { - StringReference CacheTimestampKey(CACHE_TIMESTAMP_KEY); - StringReference CacheLangcodeKey(CACHE_LANGCODE_KEY); - StringReference CacheDelimiter(CACHE_DELIMITER); - StringReference StaticDataFilename(STATIC_DATA_FILENAME); - StringReference AllRatiosDataFilename(ALL_RATIOS_DATA_FILENAME); - long long DayDuration = DAY_DURATION; - } - } -} - -CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr client) - : m_client(move(client)) - , m_loadStatus(CurrencyLoadStatus::NotLoaded) - , m_responseLanguage(L"en-US") - , m_ratioFormat(L"") - , m_timestampFormat(L"") - , m_networkManager(ref new NetworkManager()) - , m_meteredOverrideSet(false) -{ - if (GlobalizationPreferences::Languages->Size > 0) - { - m_responseLanguage = GlobalizationPreferences::Languages->GetAt(0); - } - - if (m_client != nullptr) - { - m_client->SetSourceCurrencyCode(StringReference(DefaultCurrencyCode.data())); - m_client->SetResponseLanguage(m_responseLanguage); - } - - if (CoreWindow::GetForCurrentThread() != nullptr) - { - // Must have a CoreWindow to access the resource context. - m_isRtlLanguage = LocalizationService::GetInstance()->IsRtlLayout(); - } - - m_ratioFormatter = LocalizationService::GetRegionalSettingsAwareDecimalFormatter(); - m_ratioFormatter->IsGrouped = true; - m_ratioFormatter->IsDecimalPointAlwaysDisplayed = true; - m_ratioFormatter->FractionDigits = FORMATTER_DIGIT_COUNT; - - m_ratioFormat = AppResourceProvider::GetInstance().GetResourceString(L"CurrencyFromToRatioFormat")->Data(); - m_timestampFormat = AppResourceProvider::GetInstance().GetResourceString(L"CurrencyTimestampFormat")->Data(); -} - -CurrencyDataLoader::~CurrencyDataLoader() -{ - UnregisterForNetworkBehaviorChanges(); -} - -void CurrencyDataLoader::UnregisterForNetworkBehaviorChanges() -{ - m_networkManager->NetworkBehaviorChanged -= m_networkBehaviorToken; -} - -void CurrencyDataLoader::RegisterForNetworkBehaviorChanges() -{ - UnregisterForNetworkBehaviorChanges(); - - m_networkBehaviorToken = m_networkManager->NetworkBehaviorChanged += - ref new NetworkBehaviorChangedHandler([this](NetworkAccessBehavior newBehavior) { this->OnNetworkBehaviorChanged(newBehavior); }); - - OnNetworkBehaviorChanged(NetworkManager::GetNetworkAccessBehavior()); -} - -void CurrencyDataLoader::OnNetworkBehaviorChanged(NetworkAccessBehavior newBehavior) -{ - m_networkAccessBehavior = newBehavior; - if (m_vmCallback != nullptr) - { - m_vmCallback->NetworkBehaviorChanged(static_cast(m_networkAccessBehavior)); - } -} - -bool CurrencyDataLoader::LoadFinished() -{ - return m_loadStatus != CurrencyLoadStatus::NotLoaded; -} - -bool CurrencyDataLoader::LoadedFromCache() -{ - return m_loadStatus == CurrencyLoadStatus::LoadedFromCache; -} - -bool CurrencyDataLoader::LoadedFromWeb() -{ - return m_loadStatus == CurrencyLoadStatus::LoadedFromWeb; -} - -void CurrencyDataLoader::ResetLoadStatus() -{ - m_loadStatus = CurrencyLoadStatus::NotLoaded; -} - -#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321 -void CurrencyDataLoader::LoadData() -{ - RegisterForNetworkBehaviorChanges(); - - if (!LoadFinished()) - { - create_task([this]() -> task { - vector()>> loadFunctions = { - [this]() { return TryLoadDataFromCacheAsync(); }, - [this]() { return TryLoadDataFromWebAsync(); }, - }; - - bool didLoad = false; - for (auto& f : loadFunctions) - { - didLoad = co_await f(); - if (didLoad) - { - break; - } - } - - co_return didLoad; - }) - .then( - [this](bool didLoad) { - UpdateDisplayedTimestamp(); - NotifyDataLoadFinished(didLoad); - }, - task_continuation_context::use_current()); - } -}; -#pragma optimize("", on) - -vector CurrencyDataLoader::LoadOrderedCategories() -{ - // This function should not be called - // The model will use the categories from UnitConverterDataLoader - return vector(); -} - -vector CurrencyDataLoader::LoadOrderedUnits(const UCM::Category& /*category*/) -{ - lock_guard lock(m_currencyUnitsMutex); - return m_currencyUnits; -} - -unordered_map CurrencyDataLoader::LoadOrderedRatios(const UCM::Unit& unit) -{ - lock_guard lock(m_currencyUnitsMutex); - return m_currencyRatioMap.at(unit); -} - -bool CurrencyDataLoader::SupportsCategory(const UCM::Category& target) -{ - static int currencyId = NavCategory::Serialize(ViewMode::Currency); - return target.id == currencyId; -} - -void CurrencyDataLoader::SetViewModelCallback(const shared_ptr& callback) -{ - m_vmCallback = callback; - OnNetworkBehaviorChanged(m_networkAccessBehavior); -} - -pair CurrencyDataLoader::GetCurrencySymbols(const UCM::Unit& unit1, const UCM::Unit& unit2) -{ - lock_guard lock(m_currencyUnitsMutex); - - wstring symbol1 = L""; - wstring symbol2 = L""; - - auto itr1 = m_currencyMetadata.find(unit1); - auto itr2 = m_currencyMetadata.find(unit2); - if (itr1 != m_currencyMetadata.end() && itr2 != m_currencyMetadata.end()) - { - symbol1 = (itr1->second).symbol; - symbol2 = (itr2->second).symbol; - } - - return make_pair(symbol1, symbol2); -} - -pair CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const UCM::Unit& unit1, _In_ const UCM::Unit& unit2) -{ - try - { - auto iter = m_currencyRatioMap.find(unit1); - if (iter != m_currencyRatioMap.end()) - { - unordered_map ratioMap = iter->second; - auto iter2 = ratioMap.find(unit2); - if (iter2 != ratioMap.end()) - { - double ratio = (iter2->second).ratio; - - // Round the ratio to FORMATTER_DIGIT_COUNT digits using int math. - // Ex: to round 1.23456 to three digits, use - // ((int) 1.23456 * (10^3)) / (10^3) - double scale = pow(10, FORMATTER_DIGIT_COUNT); - double rounded = static_cast(ratio * static_cast(scale)) / scale; - - wstring digitSymbol = wstring{ LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'1') }; - wstring roundedFormat = m_ratioFormatter->Format(rounded)->Data(); - - wstring ratioString = LocalizationStringUtil::GetLocalizedString( - m_ratioFormat.c_str(), digitSymbol.c_str(), unit1.abbreviation.c_str(), roundedFormat.c_str(), unit2.abbreviation.c_str()); - - wstring accessibleRatioString = LocalizationStringUtil::GetLocalizedString( - m_ratioFormat.c_str(), digitSymbol.c_str(), unit1.accessibleName.c_str(), roundedFormat.c_str(), unit2.accessibleName.c_str()); - - return make_pair(ratioString, accessibleRatioString); - } - } - } - catch (...) - { - } - - return make_pair(L"", L""); -} - -#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321 -task CurrencyDataLoader::TryLoadDataFromCacheAsync() -{ - try - { - ResetLoadStatus(); - - auto localSettings = ApplicationData::Current->LocalSettings; - if (localSettings == nullptr || !localSettings->Values->HasKey(CacheTimestampKey)) - { - co_return false; - } - - bool loadComplete = false; - m_cacheTimestamp = static_cast(localSettings->Values->Lookup(CacheTimestampKey)); - if (Utils::IsDateTimeOlderThan(m_cacheTimestamp, DAY_DURATION) && m_networkAccessBehavior == NetworkAccessBehavior::Normal) - { - loadComplete = co_await TryLoadDataFromWebAsync(); - } - - if (!loadComplete) - { - loadComplete = co_await TryFinishLoadFromCacheAsync(); - } - - co_return loadComplete; - } - catch (Exception ^ ex) - { - TraceLogger::GetInstance().LogPlatformException(__FUNCTIONW__, ex); - co_return false; - } - catch (const exception& e) - { - TraceLogger::GetInstance().LogStandardException(__FUNCTIONW__, e); - co_return false; - } - catch (...) - { - co_return false; - } -} - -task CurrencyDataLoader::TryFinishLoadFromCacheAsync() -{ - auto localSettings = ApplicationData::Current->LocalSettings; - if (localSettings == nullptr) - { - co_return false; - } - - if (!localSettings->Values->HasKey(CacheLangcodeKey) || !static_cast(localSettings->Values->Lookup(CacheLangcodeKey))->Equals(m_responseLanguage)) - { - co_return false; - } - - StorageFolder ^ localCacheFolder = ApplicationData::Current->LocalCacheFolder; - if (localCacheFolder == nullptr) - { - co_return false; - } - - String ^ staticDataResponse = co_await Utils::ReadFileFromFolder(localCacheFolder, StaticDataFilename); - String ^ allRatiosResponse = co_await Utils::ReadFileFromFolder(localCacheFolder, AllRatiosDataFilename); - - vector staticData{}; - CurrencyRatioMap ratioMap{}; - - bool didParse = TryParseWebResponses(staticDataResponse, allRatiosResponse, staticData, ratioMap); - if (!didParse) - { - co_return false; - } - - m_loadStatus = CurrencyLoadStatus::LoadedFromCache; - co_await FinalizeUnits(staticData, ratioMap); - - co_return true; -} - -task CurrencyDataLoader::TryLoadDataFromWebAsync() -{ - try - { - ResetLoadStatus(); - - if (m_client == nullptr) - { - co_return false; - } - - if (m_networkAccessBehavior == NetworkAccessBehavior::Offline || (m_networkAccessBehavior == NetworkAccessBehavior::OptIn && !m_meteredOverrideSet)) - { - co_return false; - } - - String ^ staticDataResponse = co_await m_client->GetCurrencyMetadata(); - String ^ allRatiosResponse = co_await m_client->GetCurrencyRatios(); - if (staticDataResponse == nullptr || allRatiosResponse == nullptr) - { - co_return false; - } - - vector staticData{}; - CurrencyRatioMap ratioMap{}; - - bool didParse = TryParseWebResponses(staticDataResponse, allRatiosResponse, staticData, ratioMap); - if (!didParse) - { - co_return false; - } - - // Set the timestamp before saving it below. - m_cacheTimestamp = Utils::GetUniversalSystemTime(); - - try - { - const vector> cachedFiles = { { StaticDataFilename, staticDataResponse }, { AllRatiosDataFilename, allRatiosResponse } }; - - StorageFolder ^ localCacheFolder = ApplicationData::Current->LocalCacheFolder; - for (const auto& fileInfo : cachedFiles) - { - co_await Utils::WriteFileToFolder(localCacheFolder, fileInfo.first, fileInfo.second, CreationCollisionOption::ReplaceExisting); - } - - SaveLangCodeAndTimestamp(); - } - catch (...) - { - // If we fail to save to cache it's okay, we should still continue. - } - - m_loadStatus = CurrencyLoadStatus::LoadedFromWeb; - co_await FinalizeUnits(staticData, ratioMap); - - co_return true; - } - catch (Exception ^ ex) - { - TraceLogger::GetInstance().LogPlatformException(__FUNCTIONW__, ex); - co_return false; - } - catch (const exception& e) - { - TraceLogger::GetInstance().LogStandardException(__FUNCTIONW__, e); - co_return false; - } - catch (...) - { - co_return false; - } -} - -task CurrencyDataLoader::TryLoadDataFromWebOverrideAsync() -{ - m_meteredOverrideSet = true; - bool didLoad = co_await TryLoadDataFromWebAsync(); - if (!didLoad) - { - m_loadStatus = CurrencyLoadStatus::FailedToLoad; - TraceLogger::GetInstance().LogUserRequestedRefreshFailed(); - } - - co_return didLoad; -}; -#pragma optimize("", on) - -bool CurrencyDataLoader::TryParseWebResponses( - _In_ String ^ staticDataJson, - _In_ String ^ allRatiosJson, - _Inout_ vector& staticData, - _Inout_ CurrencyRatioMap& allRatiosData) -{ - return TryParseStaticData(staticDataJson, staticData) && TryParseAllRatiosData(allRatiosJson, allRatiosData); -} - -bool CurrencyDataLoader::TryParseStaticData(_In_ String ^ rawJson, _Inout_ vector& staticData) -{ - JsonArray ^ data = nullptr; - if (!JsonArray::TryParse(rawJson, &data)) - { - return false; - } - - wstring countryCode{ L"" }; - wstring countryName{ L"" }; - wstring currencyCode{ L"" }; - wstring currencyName{ L"" }; - wstring currencySymbol{ L"" }; - - vector values = { &countryCode, &countryName, ¤cyCode, ¤cyName, ¤cySymbol }; - - assert(values.size() == STATIC_DATA_PROPERTIES.size()); - staticData.resize(size_t{ data->Size }); - for (unsigned int i = 0; i < data->Size; i++) - { - JsonObject ^ obj = data->GetAt(i)->GetObject(); - - for (size_t j = 0; j < values.size(); j++) - { - (*values[j]) = obj->GetNamedString(StringReference(STATIC_DATA_PROPERTIES[j].data()))->Data(); - } - - staticData[i] = CurrencyStaticData{ countryCode, countryName, currencyCode, currencyName, currencySymbol }; - } - - // TODO - MSFT 8533667: this sort will be replaced by a WinRT call to sort localized strings - sort(begin(staticData), end(staticData), [](CurrencyStaticData unit1, CurrencyStaticData unit2) { return unit1.countryName < unit2.countryName; }); - - return true; -} - -bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String ^ rawJson, _Inout_ CurrencyRatioMap& allRatios) -{ - JsonArray ^ data = nullptr; - if (!JsonArray::TryParse(rawJson, &data)) - { - return false; - } - - wstring sourceCurrencyCode{ DefaultCurrencyCode }; - - allRatios.clear(); - for (unsigned int i = 0; i < data->Size; i++) - { - JsonObject ^ obj = data->GetAt(i)->GetObject(); - - // Rt is ratio, An is target currency ISO code. - double relativeRatio = obj->GetNamedNumber(StringReference(RATIO_KEY)); - wstring targetCurrencyCode = obj->GetNamedString(StringReference(CURRENCY_CODE_KEY))->Data(); - - allRatios.emplace(targetCurrencyCode, CurrencyRatio{ relativeRatio, sourceCurrencyCode, targetCurrencyCode }); - } - - return true; -} - -// FinalizeUnits -// -// There are a few ways we can get the data needed for Currency Converter, including from cache or from web. -// This function accepts the data from any source, and acts as a 'last-steps' for the converter to be ready. -// This includes identifying which units will be selected and building the map of currency ratios. -#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321 -task CurrencyDataLoader::FinalizeUnits(_In_ const vector& staticData, _In_ const CurrencyRatioMap& ratioMap) -{ - unordered_map> idToUnit{}; - - SelectedUnits defaultCurrencies = co_await GetDefaultFromToCurrency(); - wstring fromCurrency = defaultCurrencies.first; - wstring toCurrency = defaultCurrencies.second; - - { - lock_guard lock(m_currencyUnitsMutex); - - int i = 1; - m_currencyUnits.clear(); - m_currencyMetadata.clear(); - bool isConversionSourceSet = false; - bool isConversionTargetSet = false; - for (const UCM::CurrencyStaticData& currencyUnit : staticData) - { - auto itr = ratioMap.find(currencyUnit.currencyCode); - if (itr != ratioMap.end() && (itr->second).ratio > 0) - { - int id = static_cast(UnitConverterUnits::UnitEnd + i); - - bool isConversionSource = (fromCurrency == currencyUnit.currencyCode); - isConversionSourceSet = isConversionSourceSet || isConversionSource; - - bool isConversionTarget = (toCurrency == currencyUnit.currencyCode); - isConversionTargetSet = isConversionTargetSet || isConversionTarget; - - UCM::Unit unit = UCM::Unit{ - id, // id - currencyUnit.currencyName, // currencyName - currencyUnit.countryName, // countryName - currencyUnit.currencyCode, // abbreviation - m_isRtlLanguage, // isRtlLanguage - isConversionSource, // isConversionSource - isConversionTarget // isConversionTarget - }; - - m_currencyUnits.push_back(unit); - m_currencyMetadata.emplace(unit, CurrencyUnitMetadata{ currencyUnit.currencySymbol }); - idToUnit.insert(pair>(unit.id, pair(unit, (itr->second).ratio))); - i++; - } - } - - if (!isConversionSourceSet || !isConversionTargetSet) - { - GuaranteeSelectedUnits(); - defaultCurrencies = { DEFAULT_FROM_CURRENCY, DEFAULT_TO_CURRENCY }; - } - - m_currencyRatioMap.clear(); - for (const auto& unit : m_currencyUnits) - { - unordered_map conversions; - double unitFactor = idToUnit[unit.id].second; - for (auto itr = idToUnit.begin(); itr != idToUnit.end(); itr++) - { - UCM::Unit targetUnit = (itr->second).first; - double conversionRatio = (itr->second).second; - UCM::ConversionData parsedData = { 1.0, 0.0, false }; - assert(unitFactor > 0); // divide by zero assert - parsedData.ratio = conversionRatio / unitFactor; - conversions.insert(make_pair(targetUnit, parsedData)); - } - - m_currencyRatioMap.insert(make_pair(unit, conversions)); - } - } // unlocked m_currencyUnitsMutex - - SaveSelectedUnitsToLocalSettings(defaultCurrencies); -}; -#pragma optimize("", on) - -void CurrencyDataLoader::GuaranteeSelectedUnits() -{ - bool isConversionSourceSet = false; - bool isConversionTargetSet = false; - for (UCM::Unit& unit : m_currencyUnits) - { - unit.isConversionSource = false; - unit.isConversionTarget = false; - - if (!isConversionSourceSet && unit.abbreviation == DEFAULT_FROM_CURRENCY) - { - unit.isConversionSource = true; - isConversionSourceSet = true; - } - if (!isConversionTargetSet && unit.abbreviation == DEFAULT_TO_CURRENCY) - { - unit.isConversionTarget = true; - isConversionTargetSet = true; - } - } -} - -void CurrencyDataLoader::NotifyDataLoadFinished(bool didLoad) -{ - if (!didLoad) - { - m_loadStatus = CurrencyLoadStatus::FailedToLoad; - } - - if (m_vmCallback != nullptr) - { - m_vmCallback->CurrencyDataLoadFinished(didLoad); - } -} - -void CurrencyDataLoader::SaveLangCodeAndTimestamp() -{ - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - if (localSettings == nullptr) - { - return; - } - - localSettings->Values->Insert(CacheTimestampKey, m_cacheTimestamp); - localSettings->Values->Insert(CacheLangcodeKey, m_responseLanguage); -} - -void CurrencyDataLoader::UpdateDisplayedTimestamp() -{ - if (m_vmCallback != nullptr) - { - wstring timestamp = GetCurrencyTimestamp(); - bool isWeekOld = Utils::IsDateTimeOlderThan(m_cacheTimestamp, WEEK_DURATION); - - m_vmCallback->CurrencyTimestampCallback(timestamp, isWeekOld); - } -} -wstring CurrencyDataLoader::GetCurrencyTimestamp() -{ - wstring timestamp = L""; - - DateTime epoch{}; - if (m_cacheTimestamp.UniversalTime != epoch.UniversalTime) - { - DateTimeFormatter ^ dateFormatter = ref new DateTimeFormatter(L"{month.abbreviated} {day.integer}, {year.full}"); - wstring date = dateFormatter->Format(m_cacheTimestamp)->Data(); - - DateTimeFormatter ^ timeFormatter = ref new DateTimeFormatter(L"shorttime"); - wstring time = timeFormatter->Format(m_cacheTimestamp)->Data(); - - timestamp = LocalizationStringUtil::GetLocalizedString(m_timestampFormat.c_str(), date.c_str(), time.c_str()); - } - - return timestamp; -} - -#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321 -task CurrencyDataLoader::GetDefaultFromToCurrency() -{ - wstring fromCurrency{ DEFAULT_FROM_CURRENCY }; - wstring toCurrency{ DEFAULT_TO_CURRENCY }; - - // First, check if we previously stored the last used currencies. - bool foundInLocalSettings = TryGetLastUsedCurrenciesFromLocalSettings(&fromCurrency, &toCurrency); - if (!foundInLocalSettings) - { - try - { - // Second, see if the current locale has preset defaults in DefaultFromToCurrency.json. - Uri ^ fileUri = ref new Uri(StringReference(DEFAULT_FROM_TO_CURRENCY_FILE_URI)); - StorageFile ^ defaultFromToCurrencyFile = co_await StorageFile::GetFileFromApplicationUriAsync(fileUri); - if (defaultFromToCurrencyFile != nullptr) - { - String ^ fileContents = co_await FileIO::ReadTextAsync(defaultFromToCurrencyFile); - JsonObject ^ fromToObject = JsonObject::Parse(fileContents); - JsonObject ^ regionalDefaults = fromToObject->GetNamedObject(m_responseLanguage); - - // Get both values before assignment in-case either fails. - String ^ selectedFrom = regionalDefaults->GetNamedString(StringReference(FROM_KEY)); - String ^ selectedTo = regionalDefaults->GetNamedString(StringReference(TO_KEY)); - - fromCurrency = selectedFrom->Data(); - toCurrency = selectedTo->Data(); - } - } - catch (...) - { - } - } - - co_return make_pair(fromCurrency, toCurrency); -}; -#pragma optimize("", on) - -bool CurrencyDataLoader::TryGetLastUsedCurrenciesFromLocalSettings(_Out_ wstring* const fromCurrency, _Out_ wstring* const toCurrency) -{ - String ^ fromKey = UnitConverterResourceKeys::CurrencyUnitFromKey; - String ^ toKey = UnitConverterResourceKeys::CurrencyUnitToKey; - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - if (localSettings != nullptr && localSettings->Values != nullptr) - { - IPropertySet ^ values = localSettings->Values; - if (values->HasKey(fromKey) && values->HasKey(toKey)) - { - *fromCurrency = static_cast(values->Lookup(fromKey))->Data(); - *toCurrency = static_cast(values->Lookup(toKey))->Data(); - - return true; - } - } - - return false; -} - -void CurrencyDataLoader::SaveSelectedUnitsToLocalSettings(_In_ const SelectedUnits& selectedUnits) -{ - String ^ fromKey = UnitConverterResourceKeys::CurrencyUnitFromKey; - String ^ toKey = UnitConverterResourceKeys::CurrencyUnitToKey; - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - if (localSettings != nullptr && localSettings->Values != nullptr) - { - IPropertySet ^ values = localSettings->Values; - values->Insert(fromKey, StringReference(selectedUnits.first.c_str())); - values->Insert(toKey, StringReference(selectedUnits.second.c_str())); - } -} diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h deleted file mode 100644 index 5221373a..00000000 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/UnitConverter.h" -#include "Common/NetworkManager.h" -#include "ICurrencyHttpClient.h" - -namespace CalculatorApp -{ - namespace ViewModel - { - public - enum class CurrencyLoadStatus - { - NotLoaded = 0, - FailedToLoad = 1, - LoadedFromCache = 2, - LoadedFromWeb = 3 - }; - - namespace UnitConverterResourceKeys - { - extern Platform::StringReference CurrencyUnitFromKey; - extern Platform::StringReference CurrencyUnitToKey; - } - - namespace CurrencyDataLoaderConstants - { - extern Platform::StringReference CacheTimestampKey; - extern Platform::StringReference CacheLangcodeKey; - extern Platform::StringReference CacheDelimiter; - extern Platform::StringReference StaticDataFilename; - extern Platform::StringReference AllRatiosDataFilename; - extern long long DayDuration; - } - - namespace UCM = UnitConversionManager; - - typedef std::unordered_map CurrencyRatioMap; - typedef std::pair SelectedUnits; - - struct CurrencyUnitMetadata - { - CurrencyUnitMetadata(const std::wstring& s) - : symbol(s) - { - } - - const std::wstring symbol; - }; - - class CurrencyDataLoader : public UCM::IConverterDataLoader, public UCM::ICurrencyConverterDataLoader - { - public: - CurrencyDataLoader(_In_ std::unique_ptr client); - ~CurrencyDataLoader(); - - bool LoadFinished(); - bool LoadedFromCache(); - bool LoadedFromWeb(); - - // IConverterDataLoader - void LoadData() override; - std::vector LoadOrderedCategories() override; - std::vector LoadOrderedUnits(const UCM::Category& category) override; - std::unordered_map LoadOrderedRatios(const UCM::Unit& unit) override; - bool SupportsCategory(const UnitConversionManager::Category& target) override; - // IConverterDataLoader - - // ICurrencyConverterDataLoader - void SetViewModelCallback(const std::shared_ptr& callback) override; - std::pair GetCurrencySymbols(const UCM::Unit& unit1, const UCM::Unit& unit2) override; - std::pair - GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override; - std::wstring GetCurrencyTimestamp() override; - - concurrency::task TryLoadDataFromCacheAsync() override; - concurrency::task TryLoadDataFromWebAsync() override; - concurrency::task TryLoadDataFromWebOverrideAsync() override; - // ICurrencyConverterDataLoader - - void OnNetworkBehaviorChanged(CalculatorApp::NetworkAccessBehavior newBehavior); - - private: - void ResetLoadStatus(); - void NotifyDataLoadFinished(bool didLoad); - - concurrency::task TryFinishLoadFromCacheAsync(); - - bool TryParseWebResponses( - _In_ Platform::String ^ staticDataJson, - _In_ Platform::String ^ allRatiosJson, - _Inout_ std::vector& staticData, - _Inout_ CurrencyRatioMap& allRatiosData); - bool TryParseStaticData(_In_ Platform::String ^ rawJson, _Inout_ std::vector& staticData); - bool TryParseAllRatiosData(_In_ Platform::String ^ rawJson, _Inout_ CurrencyRatioMap& allRatiosData); - concurrency::task FinalizeUnits(_In_ const std::vector& staticData, _In_ const CurrencyRatioMap& ratioMap); - void GuaranteeSelectedUnits(); - - void SaveLangCodeAndTimestamp(); - void UpdateDisplayedTimestamp(); - - void RegisterForNetworkBehaviorChanges(); - void UnregisterForNetworkBehaviorChanges(); - - concurrency::task GetDefaultFromToCurrency(); - bool TryGetLastUsedCurrenciesFromLocalSettings(_Out_ std::wstring* const fromCurrency, _Out_ std::wstring* const toCurrency); - void SaveSelectedUnitsToLocalSettings(_In_ const SelectedUnits& selectedUnits); - - private: - Platform::String ^ m_responseLanguage; - std::unique_ptr m_client; - - bool m_isRtlLanguage; - - std::mutex m_currencyUnitsMutex; - std::vector m_currencyUnits; - UCM::UnitToUnitToConversionDataMap m_currencyRatioMap; - std::unordered_map m_currencyMetadata; - - std::shared_ptr m_vmCallback; - - Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_ratioFormatter; - std::wstring m_ratioFormat; - Windows::Foundation::DateTime m_cacheTimestamp; - std::wstring m_timestampFormat; - - CurrencyLoadStatus m_loadStatus; - - CalculatorApp::NetworkManager ^ m_networkManager; - CalculatorApp::NetworkAccessBehavior m_networkAccessBehavior; - Windows::Foundation::EventRegistrationToken m_networkBehaviorToken; - bool m_meteredOverrideSet; - }; - } -} diff --git a/src/CalcViewModel/DataLoaders/CurrencyHttpClient.cpp b/src/CalcViewModel/DataLoaders/CurrencyHttpClient.cpp deleted file mode 100644 index 04167dab..00000000 --- a/src/CalcViewModel/DataLoaders/CurrencyHttpClient.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "CurrencyHttpClient.h" - -using namespace CalculatorApp::DataLoaders; -using namespace Platform; -using namespace std; -using namespace Windows::Foundation; -using namespace Windows::Web::Http; - -static constexpr auto sc_MetadataUriLocalizeFor = L"https://go.microsoft.com/fwlink/?linkid=2041093&localizeFor="; -static constexpr auto sc_RatiosUriRelativeTo = L"https://go.microsoft.com/fwlink/?linkid=2041339&localCurrency="; - -CurrencyHttpClient::CurrencyHttpClient() - : m_client(ref new HttpClient()) - , m_responseLanguage(L"en-US") -{ -} - -void CurrencyHttpClient::SetSourceCurrencyCode(String ^ sourceCurrencyCode) -{ - m_sourceCurrencyCode = sourceCurrencyCode; -} - -void CurrencyHttpClient::SetResponseLanguage(String ^ responseLanguage) -{ - m_responseLanguage = responseLanguage; -} - -IAsyncOperationWithProgress ^ CurrencyHttpClient::GetCurrencyMetadata() -{ - wstring uri = wstring{ sc_MetadataUriLocalizeFor } + m_responseLanguage->Data(); - auto metadataUri = ref new Uri(StringReference(uri.c_str())); - - return m_client->GetStringAsync(metadataUri); -} - -IAsyncOperationWithProgress ^ CurrencyHttpClient::GetCurrencyRatios() -{ - wstring uri = wstring{ sc_RatiosUriRelativeTo } + m_sourceCurrencyCode->Data(); - auto ratiosUri = ref new Uri(StringReference(uri.c_str())); - - return m_client->GetStringAsync(ratiosUri); -} diff --git a/src/CalcViewModel/DataLoaders/CurrencyHttpClient.h b/src/CalcViewModel/DataLoaders/CurrencyHttpClient.h deleted file mode 100644 index cfd10e7d..00000000 --- a/src/CalcViewModel/DataLoaders/CurrencyHttpClient.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "ICurrencyHttpClient.h" - -namespace CalculatorApp -{ - namespace DataLoaders - { - class CurrencyHttpClient : public ICurrencyHttpClient - { - public: - CurrencyHttpClient(); - - void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) override; - void SetResponseLanguage(Platform::String ^ responseLanguage) override; - - Windows::Foundation::IAsyncOperationWithProgress ^ GetCurrencyMetadata() override; - Windows::Foundation::IAsyncOperationWithProgress ^ GetCurrencyRatios() override; - - private: - Windows::Web::Http::HttpClient ^ m_client; - Platform::String ^ m_responseLanguage; - Platform::String ^ m_sourceCurrencyCode; - }; - } -} diff --git a/src/CalcViewModel/DataLoaders/DefaultFromToCurrency.json b/src/CalcViewModel/DataLoaders/DefaultFromToCurrency.json deleted file mode 100644 index cc664135..00000000 --- a/src/CalcViewModel/DataLoaders/DefaultFromToCurrency.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "default": { - "from": "USD", - "to": "EUR" - }, - "ar-AE": { - "from": "USD", - "to": "AED" - }, - "ar-EG": { - "from": "USD", - "to": "EGP" - }, - "ar-SA": { - "from": "USD", - "to": "SAR" - }, - "da-DK": { - "from": "DKK", - "to": "USD" - }, - "de-CH": { - "from": "EUR", - "to": "CHF" - }, - "de-DE": { - "from": "EUR", - "to": "USD" - }, - "en-AU": { - "from": "AUD", - "to": "USD" - }, - "en-CA": { - "from": "CAD", - "to": "USD" - }, - "en-ES": { - "from": "EUR", - "to": "USD" - }, - "en-GB": { - "from": "GBP", - "to": "USD" - }, - "en-IN": { - "from": "USD", - "to": "INR" - }, - "en-US": { - "from": "USD", - "to": "EUR" - }, - "es-AR": { - "from": "USD", - "to": "ARS" - }, - "es-CL": { - "from": "USD", - "to": "CLP" - }, - "es-CO": { - "from": "USD", - "to": "COP" - }, - "es-ES": { - "from": "EUR", - "to": "USD" - }, - "es-MX": { - "from": "USD", - "to": "MXN" - }, - "es-PE": { - "from": "USD", - "to": "PEN" - }, - "es-VE": { - "from": "USD", - "to": "VEF" - }, - "es-XL": { - "from": "USD", - "to": "EUR" - }, - "es-US": { - "from": "USD", - "to": "EUR" - }, - "fr-CH": { - "from": "EUR", - "to": "CHF" - }, - "fr-FR": { - "from": "EUR", - "to": "USD" - }, - "it-IT": { - "from": "EUR", - "to": "USD" - }, - "it-SM": { - "from": "EUR", - "to": "USD" - }, - "ja-JP": { - "from": "USD", - "to": "JPY" - }, - "nb-NO": { - "from": "NOK", - "to": "USD" - }, - "pt-BR": { - "from": "USD", - "to": "BRL" - }, - "sv-SE": { - "from": "SEK", - "to": "USD" - }, - "th-TH": { - "from": "USD", - "to": "THB" - }, - "zh-CN": { - "from": "USD", - "to": "CNY" - }, - "zh-HK": { - "from": "USD", - "to": "HKD" - } -} \ No newline at end of file diff --git a/src/CalcViewModel/DataLoaders/ICurrencyHttpClient.h b/src/CalcViewModel/DataLoaders/ICurrencyHttpClient.h deleted file mode 100644 index 69f23f52..00000000 --- a/src/CalcViewModel/DataLoaders/ICurrencyHttpClient.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace DataLoaders - { - class ICurrencyHttpClient - { - public: - virtual ~ICurrencyHttpClient() - { - } - - virtual void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) = 0; - virtual void SetResponseLanguage(Platform::String ^ responseLanguage) = 0; - - virtual Windows::Foundation::IAsyncOperationWithProgress ^ GetCurrencyMetadata() = 0; - virtual Windows::Foundation::IAsyncOperationWithProgress ^ GetCurrencyRatios() = 0; - }; - } -} diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h b/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h deleted file mode 100644 index 0d22a14a..00000000 --- a/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace CalculatorApp -{ - namespace ViewModel - { - private - enum UnitConverterUnits - { - UnitStart = 0, - Area_Acre = UnitStart + 1, - Area_Hectare = UnitStart + 2, - Area_SquareCentimeter = UnitStart + 3, - Area_SquareFoot = UnitStart + 4, - Area_SquareInch = UnitStart + 5, - Area_SquareKilometer = UnitStart + 6, - Area_SquareMeter = UnitStart + 7, - Area_SquareMile = UnitStart + 8, - Area_SquareMillimeter = UnitStart + 9, - Area_SquareYard = UnitStart + 10, - Data_Bit = UnitStart + 11, - Data_Byte = UnitStart + 12, - Data_Gigabit = UnitStart + 13, - Data_Gigabyte = UnitStart + 14, - Data_Kilobit = UnitStart + 15, - Data_Kilobyte = UnitStart + 16, - Data_Megabit = UnitStart + 17, - Data_Megabyte = UnitStart + 18, - Data_Petabit = UnitStart + 19, - Data_Petabyte = UnitStart + 20, - Data_Terabit = UnitStart + 21, - Data_Terabyte = UnitStart + 22, - Energy_BritishThermalUnit = UnitStart + 23, - Energy_Calorie = UnitStart + 24, - Energy_ElectronVolt = UnitStart + 25, - Energy_FootPound = UnitStart + 26, - Energy_Joule = UnitStart + 27, - Energy_Kilocalorie = UnitStart + 28, - Energy_Kilojoule = UnitStart + 29, - Length_Centimeter = UnitStart + 30, - Length_Foot = UnitStart + 31, - Length_Inch = UnitStart + 32, - Length_Kilometer = UnitStart + 33, - Length_Meter = UnitStart + 34, - Length_Micron = UnitStart + 35, - Length_Mile = UnitStart + 36, - Length_Millimeter = UnitStart + 37, - Length_Nanometer = UnitStart + 38, - Length_NauticalMile = UnitStart + 39, - Length_Yard = UnitStart + 40, - Power_BritishThermalUnitPerMinute = UnitStart + 41, - Power_FootPoundPerMinute = UnitStart + 42, - Power_Horsepower = UnitStart + 43, - Power_Kilowatt = UnitStart + 44, - Power_Watt = UnitStart + 45, - Temperature_DegreesCelsius = UnitStart + 46, - Temperature_DegreesFahrenheit = UnitStart + 47, - Temperature_Kelvin = UnitStart + 48, - Time_Day = UnitStart + 49, - Time_Hour = UnitStart + 50, - Time_Microsecond = UnitStart + 51, - Time_Millisecond = UnitStart + 52, - Time_Minute = UnitStart + 53, - Time_Second = UnitStart + 54, - Time_Week = UnitStart + 55, - Time_Year = UnitStart + 56, - Speed_CentimetersPerSecond = UnitStart + 57, - Speed_FeetPerSecond = UnitStart + 58, - Speed_KilometersPerHour = UnitStart + 59, - Speed_Knot = UnitStart + 60, - Speed_Mach = UnitStart + 61, - Speed_MetersPerSecond = UnitStart + 62, - Speed_MilesPerHour = UnitStart + 63, - Volume_CubicCentimeter = UnitStart + 64, - Volume_CubicFoot = UnitStart + 65, - Volume_CubicInch = UnitStart + 66, - Volume_CubicMeter = UnitStart + 67, - Volume_CubicYard = UnitStart + 68, - Volume_CupUS = UnitStart + 69, - Volume_FluidOunceUK = UnitStart + 70, - Volume_FluidOunceUS = UnitStart + 71, - Volume_GallonUK = UnitStart + 72, - Volume_GallonUS = UnitStart + 73, - Volume_Liter = UnitStart + 74, - Volume_Milliliter = UnitStart + 75, - Volume_PintUK = UnitStart + 76, - Volume_PintUS = UnitStart + 77, - Volume_TablespoonUS = UnitStart + 78, - Volume_TeaspoonUS = UnitStart + 79, - Volume_QuartUK = UnitStart + 80, - Volume_QuartUS = UnitStart + 81, - Weight_Carat = UnitStart + 82, - Weight_Centigram = UnitStart + 83, - Weight_Decigram = UnitStart + 84, - Weight_Decagram = UnitStart + 85, - Weight_Gram = UnitStart + 86, - Weight_Hectogram = UnitStart + 87, - Weight_Kilogram = UnitStart + 88, - Weight_LongTon = UnitStart + 89, - Weight_Milligram = UnitStart + 90, - Weight_Ounce = UnitStart + 91, - Weight_Pound = UnitStart + 92, - Weight_ShortTon = UnitStart + 93, - Weight_Stone = UnitStart + 94, - Weight_Tonne = UnitStart + 95, - Area_SoccerField = UnitStart + 99, - Data_FloppyDisk = UnitStart + 100, - Data_CD = UnitStart + 101, - Data_DVD = UnitStart + 102, - Energy_Battery = UnitStart + 103, - Length_Paperclip = UnitStart + 105, - Length_JumboJet = UnitStart + 107, - Power_LightBulb = UnitStart + 108, - Power_Horse = UnitStart + 109, - Volume_Bathtub = UnitStart + 111, - Weight_Snowflake = UnitStart + 113, - Weight_Elephant = UnitStart + 114, - Volume_TeaspoonUK = UnitStart + 115, - Volume_TablespoonUK = UnitStart + 116, - Area_Hand = UnitStart + 118, - Speed_Turtle = UnitStart + 121, - Speed_Jet = UnitStart + 122, - Volume_CoffeeCup = UnitStart + 124, - Weight_Whale = UnitStart + 123, - Volume_SwimmingPool = UnitStart + 125, - Speed_Horse = UnitStart + 126, - Area_Paper = UnitStart + 127, - Area_Castle = UnitStart + 128, - Energy_Banana = UnitStart + 129, - Energy_SliceOfCake = UnitStart + 130, - Length_Hand = UnitStart + 131, - Power_TrainEngine = UnitStart + 132, - Weight_SoccerBall = UnitStart + 133, - Angle_Degree = UnitStart + 134, - Angle_Radian = UnitStart + 135, - Angle_Gradian = UnitStart + 136, - Pressure_Atmosphere = UnitStart + 137, - Pressure_Bar = UnitStart + 138, - Pressure_KiloPascal = UnitStart + 139, - Pressure_MillimeterOfMercury = UnitStart + 140, - Pressure_Pascal = UnitStart + 141, - Pressure_PSI = UnitStart + 142, - Data_Exabits = UnitStart + 143, - Data_Exabytes = UnitStart + 144, - Data_Exbibits = UnitStart + 145, - Data_Exbibytes = UnitStart + 146, - Data_Gibibits = UnitStart + 147, - Data_Gibibytes = UnitStart + 148, - Data_Kibibits = UnitStart + 149, - Data_Kibibytes = UnitStart + 150, - Data_Mebibits = UnitStart + 151, - Data_Mebibytes = UnitStart + 152, - Data_Pebibits = UnitStart + 153, - Data_Pebibytes = UnitStart + 154, - Data_Tebibits = UnitStart + 155, - Data_Tebibytes = UnitStart + 156, - Data_Yobibits = UnitStart + 157, - Data_Yobibytes = UnitStart + 158, - Data_Yottabit = UnitStart + 159, - Data_Yottabyte = UnitStart + 160, - Data_Zebibits = UnitStart + 161, - Data_Zebibytes = UnitStart + 162, - Data_Zetabits = UnitStart + 163, - Data_Zetabytes = UnitStart + 164, - Area_Pyeong = UnitStart + 165, - UnitEnd = Area_Pyeong - }; - } -} diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp deleted file mode 100644 index e69b8e2c..00000000 --- a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp +++ /dev/null @@ -1,1003 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "Common/AppResourceProvider.h" -#include "UnitConverterDataLoader.h" -#include "UnitConverterDataConstants.h" -#include "CurrencyDataLoader.h" - -using namespace CalculatorApp::Common; -using namespace CalculatorApp::DataLoaders; -using namespace CalculatorApp::ViewModel; -using namespace Platform; -using namespace std; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::ApplicationModel::Resources::Core; -using namespace Windows::Globalization; - -static constexpr bool CONVERT_WITH_OFFSET_FIRST = true; - -UnitConverterDataLoader::UnitConverterDataLoader(GeographicRegion ^ region) - : m_currentRegionCode(region->CodeTwoLetter) -{ - m_categoryList = make_shared>(); - m_categoryToUnits = make_shared(); - m_ratioMap = make_shared(); -} - -vector UnitConverterDataLoader::LoadOrderedCategories() -{ - return *m_categoryList; -} - -vector UnitConverterDataLoader::LoadOrderedUnits(const UCM::Category& category) -{ - return m_categoryToUnits->at(category); -} - -unordered_map UnitConverterDataLoader::LoadOrderedRatios(const UCM::Unit& unit) -{ - return m_ratioMap->at(unit); -} - -bool UnitConverterDataLoader::SupportsCategory(const UCM::Category& target) -{ - shared_ptr> supportedCategories = nullptr; - if (!m_categoryList->empty()) - { - supportedCategories = m_categoryList; - } - else - { - GetCategories(supportedCategories); - } - - static int currencyId = NavCategory::Serialize(ViewMode::Currency); - auto itr = find_if(supportedCategories->begin(), supportedCategories->end(), [&](const UCM::Category& category) { - return currencyId != category.id && target.id == category.id; - }); - - return itr != supportedCategories->end(); -} - -void UnitConverterDataLoader::LoadData() -{ - unordered_map idToUnit; - - unordered_map> orderedUnitMap{}; - unordered_map> categoryToUnitConversionDataMap{}; - unordered_map> explicitConversionData{}; - - // Load categories, units and conversion data into data structures. This will be then used to populate hashmaps used by CalcEngine and UI layer - GetCategories(m_categoryList); - GetUnits(orderedUnitMap); - GetConversionData(categoryToUnitConversionDataMap); - GetExplicitConversionData(explicitConversionData); // This is needed for temperature conversions - - m_categoryToUnits->clear(); - m_ratioMap->clear(); - for (UCM::Category objectCategory : *m_categoryList) - { - ViewMode categoryViewMode = NavCategory::Deserialize(objectCategory.id); - assert(NavCategory::IsConverterViewMode(categoryViewMode)); - if (categoryViewMode == ViewMode::Currency) - { - // Currency is an ordered category but we do not want to process it here - // because this function is not thread-safe and currency data is asynchronously - // loaded. - m_categoryToUnits->insert(pair>(objectCategory, {})); - continue; - } - - vector orderedUnits = orderedUnitMap[categoryViewMode]; - vector unitList; - - // Sort the units by order - sort(orderedUnits.begin(), orderedUnits.end(), [](const OrderedUnit& first, const OrderedUnit& second) { return first.order < second.order; }); - - for (OrderedUnit u : orderedUnits) - { - unitList.push_back(static_cast(u)); - idToUnit.insert(pair(u.id, u)); - } - - // Save units per category - m_categoryToUnits->insert(pair>(objectCategory, unitList)); - - // For each unit, populate the conversion data - for (UCM::Unit unit : unitList) - { - unordered_map conversions; - - if (explicitConversionData.find(unit.id) == explicitConversionData.end()) - { - // Get the associated units for a category id - unordered_map unitConversions = categoryToUnitConversionDataMap.at(categoryViewMode); - double unitFactor = unitConversions[unit.id]; - - for (const auto& [id, conversionFactor] : unitConversions) - { - if (idToUnit.find(id) == idToUnit.end()) - { - // Optional units will not be in idToUnit but can be in unitConversions. - // For optional units that did not make it to the current set of units, just continue. - continue; - } - - UCM::ConversionData parsedData = { 1.0, 0.0, false }; - assert(conversionFactor > 0); // divide by zero assert - parsedData.ratio = unitFactor / conversionFactor; - conversions.insert(pair(idToUnit.at(id), parsedData)); - } - } - else - { - unordered_map unitConversions = explicitConversionData.at(unit.id); - for (auto itr = unitConversions.begin(); itr != unitConversions.end(); ++itr) - { - conversions.insert(pair(idToUnit.at(itr->first), itr->second)); - } - } - - m_ratioMap->insert(pair>(unit, conversions)); - } - } -} - -void UnitConverterDataLoader::GetCategories(_In_ shared_ptr> categoriesList) -{ - categoriesList->clear(); - auto converterCategory = NavCategoryGroup::CreateConverterCategory(); - for (auto const& category : converterCategory->Categories) - { - /* Id, CategoryName, SupportsNegative */ - categoriesList->emplace_back(NavCategory::Serialize(category->Mode), category->Name->Data(), category->SupportsNegative); - } -} - -void UnitConverterDataLoader::GetUnits(_In_ unordered_map>& unitMap) -{ - // US + Federated States of Micronesia, Marshall Islands, Palau - bool useUSCustomaryAndFahrenheit = - m_currentRegionCode == L"US" || m_currentRegionCode == L"FM" || m_currentRegionCode == L"MH" || m_currentRegionCode == L"PW"; - - // useUSCustomaryAndFahrenheit + Liberia - // Source: https://en.wikipedia.org/wiki/Metrication - bool useUSCustomary = useUSCustomaryAndFahrenheit || m_currentRegionCode == L"LR"; - - // Use 'Système International' (International System of Units - Metrics) - bool useSI = !useUSCustomary; - - // useUSCustomaryAndFahrenheit + the Bahamas, the Cayman Islands and Liberia - // Source: http://en.wikipedia.org/wiki/Fahrenheit - bool useFahrenheit = useUSCustomaryAndFahrenheit || m_currentRegionCode == "BS" || m_currentRegionCode == "KY" || m_currentRegionCode == "LR"; - - bool useWattInsteadOfKilowatt = m_currentRegionCode == "GB"; - - // Use Pyeong, a Korean floorspace unit. - // https://en.wikipedia.org/wiki/Korean_units_of_measurement#Area - bool usePyeong = m_currentRegionCode == L"KP" || m_currentRegionCode == L"KR"; - - vector areaUnits; - areaUnits.push_back( - OrderedUnit{ UnitConverterUnits::Area_Acre, GetLocalizedStringName(L"UnitName_Acre"), GetLocalizedStringName(L"UnitAbbreviation_Acre"), 9 }); - areaUnits.push_back( - OrderedUnit{ UnitConverterUnits::Area_Hectare, GetLocalizedStringName(L"UnitName_Hectare"), GetLocalizedStringName(L"UnitAbbreviation_Hectare"), 4 }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_SquareCentimeter, - GetLocalizedStringName(L"UnitName_SquareCentimeter"), - GetLocalizedStringName(L"UnitAbbreviation_SquareCentimeter"), - 2 }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_SquareFoot, - GetLocalizedStringName(L"UnitName_SquareFoot"), - GetLocalizedStringName(L"UnitAbbreviation_SquareFoot"), - 7, - useSI, - useUSCustomary, - false }); - areaUnits.push_back(OrderedUnit{ - UnitConverterUnits::Area_SquareInch, GetLocalizedStringName(L"UnitName_SquareInch"), GetLocalizedStringName(L"UnitAbbreviation_SquareInch"), 6 }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_SquareKilometer, - GetLocalizedStringName(L"UnitName_SquareKilometer"), - GetLocalizedStringName(L"UnitAbbreviation_SquareKilometer"), - 5 }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_SquareMeter, - GetLocalizedStringName(L"UnitName_SquareMeter"), - GetLocalizedStringName(L"UnitAbbreviation_SquareMeter"), - 3, - useUSCustomary, - useSI, - false }); - areaUnits.push_back(OrderedUnit{ - UnitConverterUnits::Area_SquareMile, GetLocalizedStringName(L"UnitName_SquareMile"), GetLocalizedStringName(L"UnitAbbreviation_SquareMile"), 10 }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_SquareMillimeter, - GetLocalizedStringName(L"UnitName_SquareMillimeter"), - GetLocalizedStringName(L"UnitAbbreviation_SquareMillimeter"), - 1 }); - areaUnits.push_back(OrderedUnit{ - UnitConverterUnits::Area_SquareYard, GetLocalizedStringName(L"UnitName_SquareYard"), GetLocalizedStringName(L"UnitAbbreviation_SquareYard"), 8 }); - areaUnits.push_back(OrderedUnit{ - UnitConverterUnits::Area_Hand, GetLocalizedStringName(L"UnitName_Hand"), GetLocalizedStringName(L"UnitAbbreviation_Hand"), 11, false, false, true }); - areaUnits.push_back(OrderedUnit{ - UnitConverterUnits::Area_Paper, GetLocalizedStringName(L"UnitName_Paper"), GetLocalizedStringName(L"UnitAbbreviation_Paper"), 12, false, false, true }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_SoccerField, - GetLocalizedStringName(L"UnitName_SoccerField"), - GetLocalizedStringName(L"UnitAbbreviation_SoccerField"), - 13, - false, - false, - true }); - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_Castle, - GetLocalizedStringName(L"UnitName_Castle"), - GetLocalizedStringName(L"UnitAbbreviation_Castle"), - 14, - false, - false, - true }); - if (usePyeong) - { - areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_Pyeong, - GetLocalizedStringName(L"UnitName_Pyeong"), - GetLocalizedStringName(L"UnitAbbreviation_Pyeong"), - 15, - false, - false, - false }); - } - unitMap.emplace(ViewMode::Area, areaUnits); - - vector dataUnits; - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Bit, GetLocalizedStringName(L"UnitName_Bit"), GetLocalizedStringName(L"UnitAbbreviation_Bit"), 1 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Byte, GetLocalizedStringName(L"UnitName_Byte"), GetLocalizedStringName(L"UnitAbbreviation_Byte"), 2 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Exabits, GetLocalizedStringName(L"UnitName_Exabits"), GetLocalizedStringName(L"UnitAbbreviation_Exabits"), 23 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Exabytes, GetLocalizedStringName(L"UnitName_Exabytes"), GetLocalizedStringName(L"UnitAbbreviation_Exabytes"), 25 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Exbibits, GetLocalizedStringName(L"UnitName_Exbibits"), GetLocalizedStringName(L"UnitAbbreviation_Exbibits"), 24 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Exbibytes, GetLocalizedStringName(L"UnitName_Exbibytes"), GetLocalizedStringName(L"UnitAbbreviation_Exbibytes"), 26 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Gibibits, GetLocalizedStringName(L"UnitName_Gibibits"), GetLocalizedStringName(L"UnitAbbreviation_Gibibits"), 12 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Gibibytes, GetLocalizedStringName(L"UnitName_Gibibytes"), GetLocalizedStringName(L"UnitAbbreviation_Gibibytes"), 14 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Gigabit, GetLocalizedStringName(L"UnitName_Gigabit"), GetLocalizedStringName(L"UnitAbbreviation_Gigabit"), 11 }); - dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gigabyte, - GetLocalizedStringName(L"UnitName_Gigabyte"), - GetLocalizedStringName(L"UnitAbbreviation_Gigabyte"), - 13, - true, - false, - false }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Kibibits, GetLocalizedStringName(L"UnitName_Kibibits"), GetLocalizedStringName(L"UnitAbbreviation_Kibibits"), 4 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Kibibytes, GetLocalizedStringName(L"UnitName_Kibibytes"), GetLocalizedStringName(L"UnitAbbreviation_Kibibytes"), 6 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Kilobit, GetLocalizedStringName(L"UnitName_Kilobit"), GetLocalizedStringName(L"UnitAbbreviation_Kilobit"), 3 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Kilobyte, GetLocalizedStringName(L"UnitName_Kilobyte"), GetLocalizedStringName(L"UnitAbbreviation_Kilobyte"), 5 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Mebibits, GetLocalizedStringName(L"UnitName_Mebibits"), GetLocalizedStringName(L"UnitAbbreviation_Mebibits"), 8 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Mebibytes, GetLocalizedStringName(L"UnitName_Mebibytes"), GetLocalizedStringName(L"UnitAbbreviation_Mebibytes"), 10 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Megabit, GetLocalizedStringName(L"UnitName_Megabit"), GetLocalizedStringName(L"UnitAbbreviation_Megabit"), 7 }); - dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Megabyte, - GetLocalizedStringName(L"UnitName_Megabyte"), - GetLocalizedStringName(L"UnitAbbreviation_Megabyte"), - 9, - false, - true, - false }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Pebibits, GetLocalizedStringName(L"UnitName_Pebibits"), GetLocalizedStringName(L"UnitAbbreviation_Pebibits"), 20 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Pebibytes, GetLocalizedStringName(L"UnitName_Pebibytes"), GetLocalizedStringName(L"UnitAbbreviation_Pebibytes"), 22 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Petabit, GetLocalizedStringName(L"UnitName_Petabit"), GetLocalizedStringName(L"UnitAbbreviation_Petabit"), 19 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Petabyte, GetLocalizedStringName(L"UnitName_Petabyte"), GetLocalizedStringName(L"UnitAbbreviation_Petabyte"), 21 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Tebibits, GetLocalizedStringName(L"UnitName_Tebibits"), GetLocalizedStringName(L"UnitAbbreviation_Tebibits"), 16 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Tebibytes, GetLocalizedStringName(L"UnitName_Tebibytes"), GetLocalizedStringName(L"UnitAbbreviation_Tebibytes"), 18 }); - dataUnits.push_back( - OrderedUnit{ UnitConverterUnits::Data_Terabit, GetLocalizedStringName(L"UnitName_Terabit"), GetLocalizedStringName(L"UnitAbbreviation_Terabit"), 15 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Terabyte, GetLocalizedStringName(L"UnitName_Terabyte"), GetLocalizedStringName(L"UnitAbbreviation_Terabyte"), 17 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Yobibits, GetLocalizedStringName(L"UnitName_Yobibits"), GetLocalizedStringName(L"UnitAbbreviation_Yobibits"), 32 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Yobibytes, GetLocalizedStringName(L"UnitName_Yobibytes"), GetLocalizedStringName(L"UnitAbbreviation_Yobibytes"), 34 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Yottabit, GetLocalizedStringName(L"UnitName_Yottabit"), GetLocalizedStringName(L"UnitAbbreviation_Yottabit"), 31 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Yottabyte, GetLocalizedStringName(L"UnitName_Yottabyte"), GetLocalizedStringName(L"UnitAbbreviation_Yottabyte"), 33 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Zebibits, GetLocalizedStringName(L"UnitName_Zebibits"), GetLocalizedStringName(L"UnitAbbreviation_Zebibits"), 28 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Zebibytes, GetLocalizedStringName(L"UnitName_Zebibytes"), GetLocalizedStringName(L"UnitAbbreviation_Zebibytes"), 30 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Zetabits, GetLocalizedStringName(L"UnitName_Zetabits"), GetLocalizedStringName(L"UnitAbbreviation_Zetabits"), 27 }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_Zetabytes, GetLocalizedStringName(L"UnitName_Zetabytes"), GetLocalizedStringName(L"UnitAbbreviation_Zetabytes"), 29 }); - dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_FloppyDisk, - GetLocalizedStringName(L"UnitName_FloppyDisk"), - GetLocalizedStringName(L"UnitAbbreviation_FloppyDisk"), - 13, - false, - false, - true }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_CD, GetLocalizedStringName(L"UnitName_CD"), GetLocalizedStringName(L"UnitAbbreviation_CD"), 14, false, false, true }); - dataUnits.push_back(OrderedUnit{ - UnitConverterUnits::Data_DVD, GetLocalizedStringName(L"UnitName_DVD"), GetLocalizedStringName(L"UnitAbbreviation_DVD"), 15, false, false, true }); - unitMap.emplace(ViewMode::Data, dataUnits); - - vector energyUnits; - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_BritishThermalUnit, - GetLocalizedStringName(L"UnitName_BritishThermalUnit"), - GetLocalizedStringName(L"UnitAbbreviation_BritishThermalUnit"), - 7 }); - energyUnits.push_back( - OrderedUnit{ UnitConverterUnits::Energy_Calorie, GetLocalizedStringName(L"UnitName_Calorie"), GetLocalizedStringName(L"UnitAbbreviation_Calorie"), 4 }); - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_ElectronVolt, - GetLocalizedStringName(L"UnitName_Electron-Volt"), - GetLocalizedStringName(L"UnitAbbreviation_Electron-Volt"), - 1 }); - energyUnits.push_back(OrderedUnit{ - UnitConverterUnits::Energy_FootPound, GetLocalizedStringName(L"UnitName_Foot-Pound"), GetLocalizedStringName(L"UnitAbbreviation_Foot-Pound"), 6 }); - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_Joule, - GetLocalizedStringName(L"UnitName_Joule"), - GetLocalizedStringName(L"UnitAbbreviation_Joule"), - 2, - true, - false, - false }); - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_Kilocalorie, - GetLocalizedStringName(L"UnitName_Kilocalorie"), - GetLocalizedStringName(L"UnitAbbreviation_Kilocalorie"), - 5, - false, - true, - false }); - energyUnits.push_back(OrderedUnit{ - UnitConverterUnits::Energy_Kilojoule, GetLocalizedStringName(L"UnitName_Kilojoule"), GetLocalizedStringName(L"UnitAbbreviation_Kilojoule"), 3 }); - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_Battery, - GetLocalizedStringName(L"UnitName_Battery"), - GetLocalizedStringName(L"UnitAbbreviation_Battery"), - 8, - false, - false, - true }); - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_Banana, - GetLocalizedStringName(L"UnitName_Banana"), - GetLocalizedStringName(L"UnitAbbreviation_Banana"), - 9, - false, - false, - true }); - energyUnits.push_back(OrderedUnit{ UnitConverterUnits::Energy_SliceOfCake, - GetLocalizedStringName(L"UnitName_SliceOfCake"), - GetLocalizedStringName(L"UnitAbbreviation_SliceOfCake"), - 10, - false, - false, - true }); - unitMap.emplace(ViewMode::Energy, energyUnits); - - vector lengthUnits; - lengthUnits.push_back(OrderedUnit{ UnitConverterUnits::Length_Centimeter, - GetLocalizedStringName(L"UnitName_Centimeter"), - GetLocalizedStringName(L"UnitAbbreviation_Centimeter"), - 4, - useUSCustomary, - useSI, - false }); - lengthUnits.push_back( - OrderedUnit{ UnitConverterUnits::Length_Foot, GetLocalizedStringName(L"UnitName_Foot"), GetLocalizedStringName(L"UnitAbbreviation_Foot"), 8 }); - lengthUnits.push_back(OrderedUnit{ UnitConverterUnits::Length_Inch, - GetLocalizedStringName(L"UnitName_Inch"), - GetLocalizedStringName(L"UnitAbbreviation_Inch"), - 7, - useSI, - useUSCustomary, - false }); - lengthUnits.push_back(OrderedUnit{ - UnitConverterUnits::Length_Kilometer, GetLocalizedStringName(L"UnitName_Kilometer"), GetLocalizedStringName(L"UnitAbbreviation_Kilometer"), 6 }); - lengthUnits.push_back( - OrderedUnit{ UnitConverterUnits::Length_Meter, GetLocalizedStringName(L"UnitName_Meter"), GetLocalizedStringName(L"UnitAbbreviation_Meter"), 5 }); - lengthUnits.push_back( - OrderedUnit{ UnitConverterUnits::Length_Micron, GetLocalizedStringName(L"UnitName_Micron"), GetLocalizedStringName(L"UnitAbbreviation_Micron"), 2 }); - lengthUnits.push_back( - OrderedUnit{ UnitConverterUnits::Length_Mile, GetLocalizedStringName(L"UnitName_Mile"), GetLocalizedStringName(L"UnitAbbreviation_Mile"), 10 }); - lengthUnits.push_back(OrderedUnit{ - UnitConverterUnits::Length_Millimeter, GetLocalizedStringName(L"UnitName_Millimeter"), GetLocalizedStringName(L"UnitAbbreviation_Millimeter"), 3 }); - lengthUnits.push_back(OrderedUnit{ - UnitConverterUnits::Length_Nanometer, GetLocalizedStringName(L"UnitName_Nanometer"), GetLocalizedStringName(L"UnitAbbreviation_Nanometer"), 1 }); - lengthUnits.push_back(OrderedUnit{ UnitConverterUnits::Length_NauticalMile, - GetLocalizedStringName(L"UnitName_NauticalMile"), - GetLocalizedStringName(L"UnitAbbreviation_NauticalMile"), - 11 }); - lengthUnits.push_back( - OrderedUnit{ UnitConverterUnits::Length_Yard, GetLocalizedStringName(L"UnitName_Yard"), GetLocalizedStringName(L"UnitAbbreviation_Yard"), 9 }); - lengthUnits.push_back(OrderedUnit{ UnitConverterUnits::Length_Paperclip, - GetLocalizedStringName(L"UnitName_Paperclip"), - GetLocalizedStringName(L"UnitAbbreviation_Paperclip"), - 12, - false, - false, - true }); - lengthUnits.push_back(OrderedUnit{ - UnitConverterUnits::Length_Hand, GetLocalizedStringName(L"UnitName_Hand"), GetLocalizedStringName(L"UnitAbbreviation_Hand"), 13, false, false, true }); - lengthUnits.push_back(OrderedUnit{ UnitConverterUnits::Length_JumboJet, - GetLocalizedStringName(L"UnitName_JumboJet"), - GetLocalizedStringName(L"UnitAbbreviation_JumboJet"), - 14, - false, - false, - true }); - unitMap.emplace(ViewMode::Length, lengthUnits); - - vector powerUnits; - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_BritishThermalUnitPerMinute, - GetLocalizedStringName(L"UnitName_BTUPerMinute"), - GetLocalizedStringName(L"UnitAbbreviation_BTUPerMinute"), - 5 }); - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_FootPoundPerMinute, - GetLocalizedStringName(L"UnitName_Foot-PoundPerMinute"), - GetLocalizedStringName(L"UnitAbbreviation_Foot-PoundPerMinute"), - 4 }); - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_Horsepower, - GetLocalizedStringName(L"UnitName_Horsepower"), - GetLocalizedStringName(L"UnitAbbreviation_Horsepower"), - 3, - false, - true, - false }); - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_Kilowatt, - GetLocalizedStringName(L"UnitName_Kilowatt"), - GetLocalizedStringName(L"UnitAbbreviation_Kilowatt"), - 2, - !useWattInsteadOfKilowatt }); - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_Watt, - GetLocalizedStringName(L"UnitName_Watt"), - GetLocalizedStringName(L"UnitAbbreviation_Watt"), - 1, - useWattInsteadOfKilowatt }); - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_LightBulb, - GetLocalizedStringName(L"UnitName_LightBulb"), - GetLocalizedStringName(L"UnitAbbreviation_LightBulb"), - 6, - false, - false, - true }); - powerUnits.push_back(OrderedUnit{ - UnitConverterUnits::Power_Horse, GetLocalizedStringName(L"UnitName_Horse"), GetLocalizedStringName(L"UnitAbbreviation_Horse"), 7, false, false, true }); - powerUnits.push_back(OrderedUnit{ UnitConverterUnits::Power_TrainEngine, - GetLocalizedStringName(L"UnitName_TrainEngine"), - GetLocalizedStringName(L"UnitAbbreviation_TrainEngine"), - 8, - false, - false, - true }); - unitMap.emplace(ViewMode::Power, powerUnits); - - vector tempUnits; - tempUnits.push_back(OrderedUnit{ UnitConverterUnits::Temperature_DegreesCelsius, - GetLocalizedStringName(L"UnitName_DegreesCelsius"), - GetLocalizedStringName(L"UnitAbbreviation_DegreesCelsius"), - 1, - useFahrenheit, - !useFahrenheit, - false }); - tempUnits.push_back(OrderedUnit{ UnitConverterUnits::Temperature_DegreesFahrenheit, - GetLocalizedStringName(L"UnitName_DegreesFahrenheit"), - GetLocalizedStringName(L"UnitAbbreviation_DegreesFahrenheit"), - 2, - !useFahrenheit, - useFahrenheit, - false }); - tempUnits.push_back(OrderedUnit{ - UnitConverterUnits::Temperature_Kelvin, GetLocalizedStringName(L"UnitName_Kelvin"), GetLocalizedStringName(L"UnitAbbreviation_Kelvin"), 3 }); - unitMap.emplace(ViewMode::Temperature, tempUnits); - - vector timeUnits; - timeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Time_Day, GetLocalizedStringName(L"UnitName_Day"), GetLocalizedStringName(L"UnitAbbreviation_Day"), 6 }); - timeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Time_Hour, GetLocalizedStringName(L"UnitName_Hour"), GetLocalizedStringName(L"UnitAbbreviation_Hour"), 5, true, false, false }); - timeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Time_Microsecond, GetLocalizedStringName(L"UnitName_Microsecond"), GetLocalizedStringName(L"UnitAbbreviation_Microsecond"), 1 }); - timeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Time_Millisecond, GetLocalizedStringName(L"UnitName_Millisecond"), GetLocalizedStringName(L"UnitAbbreviation_Millisecond"), 2 }); - timeUnits.push_back(OrderedUnit{ UnitConverterUnits::Time_Minute, - GetLocalizedStringName(L"UnitName_Minute"), - GetLocalizedStringName(L"UnitAbbreviation_Minute"), - 4, - false, - true, - false }); - timeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Time_Second, GetLocalizedStringName(L"UnitName_Second"), GetLocalizedStringName(L"UnitAbbreviation_Second"), 3 }); - timeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Time_Week, GetLocalizedStringName(L"UnitName_Week"), GetLocalizedStringName(L"UnitAbbreviation_Week"), 7 }); - timeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Time_Year, GetLocalizedStringName(L"UnitName_Year"), GetLocalizedStringName(L"UnitAbbreviation_Year"), 8 }); - unitMap.emplace(ViewMode::Time, timeUnits); - - vector speedUnits; - speedUnits.push_back(OrderedUnit{ UnitConverterUnits::Speed_CentimetersPerSecond, - GetLocalizedStringName(L"UnitName_CentimetersPerSecond"), - GetLocalizedStringName(L"UnitAbbreviation_CentimetersPerSecond"), - 1 }); - speedUnits.push_back(OrderedUnit{ UnitConverterUnits::Speed_FeetPerSecond, - GetLocalizedStringName(L"UnitName_FeetPerSecond"), - GetLocalizedStringName(L"UnitAbbreviation_FeetPerSecond"), - 4 }); - speedUnits.push_back(OrderedUnit{ UnitConverterUnits::Speed_KilometersPerHour, - GetLocalizedStringName(L"UnitName_KilometersPerHour"), - GetLocalizedStringName(L"UnitAbbreviation_KilometersPerHour"), - 3, - useUSCustomary, - useSI, - false }); - speedUnits.push_back( - OrderedUnit{ UnitConverterUnits::Speed_Knot, GetLocalizedStringName(L"UnitName_Knot"), GetLocalizedStringName(L"UnitAbbreviation_Knot"), 6 }); - speedUnits.push_back( - OrderedUnit{ UnitConverterUnits::Speed_Mach, GetLocalizedStringName(L"UnitName_Mach"), GetLocalizedStringName(L"UnitAbbreviation_Mach"), 7 }); - speedUnits.push_back(OrderedUnit{ UnitConverterUnits::Speed_MetersPerSecond, - GetLocalizedStringName(L"UnitName_MetersPerSecond"), - GetLocalizedStringName(L"UnitAbbreviation_MetersPerSecond"), - 2 }); - speedUnits.push_back(OrderedUnit{ UnitConverterUnits::Speed_MilesPerHour, - GetLocalizedStringName(L"UnitName_MilesPerHour"), - GetLocalizedStringName(L"UnitAbbreviation_MilesPerHour"), - 5, - useSI, - useUSCustomary, - false }); - speedUnits.push_back(OrderedUnit{ UnitConverterUnits::Speed_Turtle, - GetLocalizedStringName(L"UnitName_Turtle"), - GetLocalizedStringName(L"UnitAbbreviation_Turtle"), - 8, - false, - false, - true }); - speedUnits.push_back(OrderedUnit{ - UnitConverterUnits::Speed_Horse, GetLocalizedStringName(L"UnitName_Horse"), GetLocalizedStringName(L"UnitAbbreviation_Horse"), 9, false, false, true }); - speedUnits.push_back(OrderedUnit{ - UnitConverterUnits::Speed_Jet, GetLocalizedStringName(L"UnitName_Jet"), GetLocalizedStringName(L"UnitAbbreviation_Jet"), 10, false, false, true }); - unitMap.emplace(ViewMode::Speed, speedUnits); - - vector volumeUnits; - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_CubicCentimeter, - GetLocalizedStringName(L"UnitName_CubicCentimeter"), - GetLocalizedStringName(L"UnitAbbreviation_CubicCentimeter"), - 2 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_CubicFoot, GetLocalizedStringName(L"UnitName_CubicFoot"), GetLocalizedStringName(L"UnitAbbreviation_CubicFoot"), 13 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_CubicInch, GetLocalizedStringName(L"UnitName_CubicInch"), GetLocalizedStringName(L"UnitAbbreviation_CubicInch"), 12 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_CubicMeter, GetLocalizedStringName(L"UnitName_CubicMeter"), GetLocalizedStringName(L"UnitAbbreviation_CubicMeter"), 4 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_CubicYard, GetLocalizedStringName(L"UnitName_CubicYard"), GetLocalizedStringName(L"UnitAbbreviation_CubicYard"), 14 }); - volumeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Volume_CupUS, GetLocalizedStringName(L"UnitName_CupUS"), GetLocalizedStringName(L"UnitAbbreviation_CupUS"), 8 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_FluidOunceUK, - GetLocalizedStringName(L"UnitName_FluidOunceUK"), - GetLocalizedStringName(L"UnitAbbreviation_FluidOunceUK"), - 17 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_FluidOunceUS, - GetLocalizedStringName(L"UnitName_FluidOunceUS"), - GetLocalizedStringName(L"UnitAbbreviation_FluidOunceUS"), - 7 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_GallonUK, GetLocalizedStringName(L"UnitName_GallonUK"), GetLocalizedStringName(L"UnitAbbreviation_GallonUK"), 20 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_GallonUS, GetLocalizedStringName(L"UnitName_GallonUS"), GetLocalizedStringName(L"UnitAbbreviation_GallonUS"), 11 }); - volumeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Volume_Liter, GetLocalizedStringName(L"UnitName_Liter"), GetLocalizedStringName(L"UnitAbbreviation_Liter"), 3 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_Milliliter, - GetLocalizedStringName(L"UnitName_Milliliter"), - GetLocalizedStringName(L"UnitAbbreviation_Milliliter"), - 1, - useUSCustomary, - useSI }); - volumeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Volume_PintUK, GetLocalizedStringName(L"UnitName_PintUK"), GetLocalizedStringName(L"UnitAbbreviation_PintUK"), 18 }); - volumeUnits.push_back( - OrderedUnit{ UnitConverterUnits::Volume_PintUS, GetLocalizedStringName(L"UnitName_PintUS"), GetLocalizedStringName(L"UnitAbbreviation_PintUS"), 9 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_TablespoonUS, - GetLocalizedStringName(L"UnitName_TablespoonUS"), - GetLocalizedStringName(L"UnitAbbreviation_TablespoonUS"), - 6 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_TeaspoonUS, - GetLocalizedStringName(L"UnitName_TeaspoonUS"), - GetLocalizedStringName(L"UnitAbbreviation_TeaspoonUS"), - 5, - useSI, - useUSCustomary && m_currentRegionCode != "GB" }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_QuartUK, GetLocalizedStringName(L"UnitName_QuartUK"), GetLocalizedStringName(L"UnitAbbreviation_QuartUK"), 19 }); - volumeUnits.push_back(OrderedUnit{ - UnitConverterUnits::Volume_QuartUS, GetLocalizedStringName(L"UnitName_QuartUS"), GetLocalizedStringName(L"UnitAbbreviation_QuartUS"), 10 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_TeaspoonUK, - GetLocalizedStringName(L"UnitName_TeaspoonUK"), - GetLocalizedStringName(L"UnitAbbreviation_TeaspoonUK"), - 15, - false, - useUSCustomary && m_currentRegionCode == "GB" }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_TablespoonUK, - GetLocalizedStringName(L"UnitName_TablespoonUK"), - GetLocalizedStringName(L"UnitAbbreviation_TablespoonUK"), - 16 }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_CoffeeCup, - GetLocalizedStringName(L"UnitName_CoffeeCup"), - GetLocalizedStringName(L"UnitAbbreviation_CoffeeCup"), - 22, - false, - false, - true }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_Bathtub, - GetLocalizedStringName(L"UnitName_Bathtub"), - GetLocalizedStringName(L"UnitAbbreviation_Bathtub"), - 23, - false, - false, - true }); - volumeUnits.push_back(OrderedUnit{ UnitConverterUnits::Volume_SwimmingPool, - GetLocalizedStringName(L"UnitName_SwimmingPool"), - GetLocalizedStringName(L"UnitAbbreviation_SwimmingPool"), - 24, - false, - false, - true }); - unitMap.emplace(ViewMode::Volume, volumeUnits); - - vector weightUnits; - weightUnits.push_back( - OrderedUnit{ UnitConverterUnits::Weight_Carat, GetLocalizedStringName(L"UnitName_Carat"), GetLocalizedStringName(L"UnitAbbreviation_Carat"), 1 }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_Centigram, GetLocalizedStringName(L"UnitName_Centigram"), GetLocalizedStringName(L"UnitAbbreviation_Centigram"), 3 }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_Decigram, GetLocalizedStringName(L"UnitName_Decigram"), GetLocalizedStringName(L"UnitAbbreviation_Decigram"), 4 }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_Decagram, GetLocalizedStringName(L"UnitName_Decagram"), GetLocalizedStringName(L"UnitAbbreviation_Decagram"), 6 }); - weightUnits.push_back( - OrderedUnit{ UnitConverterUnits::Weight_Gram, GetLocalizedStringName(L"UnitName_Gram"), GetLocalizedStringName(L"UnitAbbreviation_Gram"), 5 }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_Hectogram, GetLocalizedStringName(L"UnitName_Hectogram"), GetLocalizedStringName(L"UnitAbbreviation_Hectogram"), 7 }); - weightUnits.push_back(OrderedUnit{ UnitConverterUnits::Weight_Kilogram, - GetLocalizedStringName(L"UnitName_Kilogram"), - GetLocalizedStringName(L"UnitAbbreviation_Kilogram"), - 8, - useUSCustomary, - useSI }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_LongTon, GetLocalizedStringName(L"UnitName_LongTon"), GetLocalizedStringName(L"UnitAbbreviation_LongTon"), 14 }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_Milligram, GetLocalizedStringName(L"UnitName_Milligram"), GetLocalizedStringName(L"UnitAbbreviation_Milligram"), 2 }); - weightUnits.push_back( - OrderedUnit{ UnitConverterUnits::Weight_Ounce, GetLocalizedStringName(L"UnitName_Ounce"), GetLocalizedStringName(L"UnitAbbreviation_Ounce"), 10 }); - weightUnits.push_back(OrderedUnit{ UnitConverterUnits::Weight_Pound, - GetLocalizedStringName(L"UnitName_Pound"), - GetLocalizedStringName(L"UnitAbbreviation_Pound"), - 11, - useSI, - useUSCustomary }); - weightUnits.push_back(OrderedUnit{ - UnitConverterUnits::Weight_ShortTon, GetLocalizedStringName(L"UnitName_ShortTon"), GetLocalizedStringName(L"UnitAbbreviation_ShortTon"), 13 }); - weightUnits.push_back( - OrderedUnit{ UnitConverterUnits::Weight_Stone, GetLocalizedStringName(L"UnitName_Stone"), GetLocalizedStringName(L"UnitAbbreviation_Stone"), 12 }); - weightUnits.push_back( - OrderedUnit{ UnitConverterUnits::Weight_Tonne, GetLocalizedStringName(L"UnitName_Tonne"), GetLocalizedStringName(L"UnitAbbreviation_Tonne"), 9 }); - weightUnits.push_back(OrderedUnit{ UnitConverterUnits::Weight_Snowflake, - GetLocalizedStringName(L"UnitName_Snowflake"), - GetLocalizedStringName(L"UnitAbbreviation_Snowflake"), - 15, - false, - false, - true }); - weightUnits.push_back(OrderedUnit{ UnitConverterUnits::Weight_SoccerBall, - GetLocalizedStringName(L"UnitName_SoccerBall"), - GetLocalizedStringName(L"UnitAbbreviation_SoccerBall"), - 16, - false, - false, - true }); - weightUnits.push_back(OrderedUnit{ UnitConverterUnits::Weight_Elephant, - GetLocalizedStringName(L"UnitName_Elephant"), - GetLocalizedStringName(L"UnitAbbreviation_Elephant"), - 17, - false, - false, - true }); - weightUnits.push_back(OrderedUnit{ UnitConverterUnits::Weight_Whale, - GetLocalizedStringName(L"UnitName_Whale"), - GetLocalizedStringName(L"UnitAbbreviation_Whale"), - 18, - false, - false, - true }); - unitMap.emplace(ViewMode::Weight, weightUnits); - - vector pressureUnits; - pressureUnits.push_back(OrderedUnit{ UnitConverterUnits::Pressure_Atmosphere, - GetLocalizedStringName(L"UnitName_Atmosphere"), - GetLocalizedStringName(L"UnitAbbreviation_Atmosphere"), - 1, - true, - false, - false }); - pressureUnits.push_back(OrderedUnit{ - UnitConverterUnits::Pressure_Bar, GetLocalizedStringName(L"UnitName_Bar"), GetLocalizedStringName(L"UnitAbbreviation_Bar"), 2, false, true, false }); - pressureUnits.push_back(OrderedUnit{ - UnitConverterUnits::Pressure_KiloPascal, GetLocalizedStringName(L"UnitName_KiloPascal"), GetLocalizedStringName(L"UnitAbbreviation_KiloPascal"), 3 }); - pressureUnits.push_back(OrderedUnit{ UnitConverterUnits::Pressure_MillimeterOfMercury, - GetLocalizedStringName(L"UnitName_MillimeterOfMercury "), - GetLocalizedStringName(L"UnitAbbreviation_MillimeterOfMercury "), - 4 }); - pressureUnits.push_back( - OrderedUnit{ UnitConverterUnits::Pressure_Pascal, GetLocalizedStringName(L"UnitName_Pascal"), GetLocalizedStringName(L"UnitAbbreviation_Pascal"), 5 }); - pressureUnits.push_back(OrderedUnit{ - UnitConverterUnits::Pressure_PSI, GetLocalizedStringName(L"UnitName_PSI"), GetLocalizedStringName(L"UnitAbbreviation_PSI"), 6, false, false, false }); - unitMap.emplace(ViewMode::Pressure, pressureUnits); - - vector angleUnits; - angleUnits.push_back(OrderedUnit{ UnitConverterUnits::Angle_Degree, - GetLocalizedStringName(L"UnitName_Degree"), - GetLocalizedStringName(L"UnitAbbreviation_Degree"), - 1, - true, - false, - false }); - angleUnits.push_back(OrderedUnit{ UnitConverterUnits::Angle_Radian, - GetLocalizedStringName(L"UnitName_Radian"), - GetLocalizedStringName(L"UnitAbbreviation_Radian"), - 2, - false, - true, - false }); - angleUnits.push_back( - OrderedUnit{ UnitConverterUnits::Angle_Gradian, GetLocalizedStringName(L"UnitName_Gradian"), GetLocalizedStringName(L"UnitAbbreviation_Gradian"), 3 }); - unitMap.emplace(ViewMode::Angle, angleUnits); -} - -void UnitConverterDataLoader::GetConversionData(_In_ unordered_map>& categoryToUnitConversionMap) -{ - /*categoryId, UnitId, factor*/ - static const vector unitDataList = { { ViewMode::Area, UnitConverterUnits::Area_Acre, 4046.8564224 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareMeter, 1 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareFoot, 0.09290304 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareYard, 0.83612736 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareMillimeter, 0.000001 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareCentimeter, 0.0001 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareInch, 0.00064516 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareMile, 2589988.110336 }, - { ViewMode::Area, UnitConverterUnits::Area_SquareKilometer, 1000000 }, - { ViewMode::Area, UnitConverterUnits::Area_Hectare, 10000 }, - { ViewMode::Area, UnitConverterUnits::Area_Hand, 0.012516104 }, - { ViewMode::Area, UnitConverterUnits::Area_Paper, 0.06032246 }, - { ViewMode::Area, UnitConverterUnits::Area_SoccerField, 10869.66 }, - { ViewMode::Area, UnitConverterUnits::Area_Castle, 100000 }, - { ViewMode::Area, UnitConverterUnits::Area_Pyeong, 400.0 / 121.0 }, - - { ViewMode::Data, UnitConverterUnits::Data_Bit, 0.000000125 }, - { ViewMode::Data, UnitConverterUnits::Data_Byte, 0.000001 }, - { ViewMode::Data, UnitConverterUnits::Data_Kilobyte, 0.001 }, - { ViewMode::Data, UnitConverterUnits::Data_Megabyte, 1 }, - { ViewMode::Data, UnitConverterUnits::Data_Gigabyte, 1000 }, - { ViewMode::Data, UnitConverterUnits::Data_Terabyte, 1000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Petabyte, 1000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Exabytes, 1000000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Zetabytes, 1000000000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Yottabyte, 1000000000000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Kilobit, 0.000125 }, - { ViewMode::Data, UnitConverterUnits::Data_Megabit, 0.125 }, - { ViewMode::Data, UnitConverterUnits::Data_Gigabit, 125 }, - { ViewMode::Data, UnitConverterUnits::Data_Terabit, 125000 }, - { ViewMode::Data, UnitConverterUnits::Data_Petabit, 125000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Exabits, 125000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Zetabits, 125000000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Yottabit, 125000000000000000 }, - { ViewMode::Data, UnitConverterUnits::Data_Gibibits, 134.217728 }, - { ViewMode::Data, UnitConverterUnits::Data_Gibibytes, 1073.741824 }, - { ViewMode::Data, UnitConverterUnits::Data_Kibibits, 0.000128 }, - { ViewMode::Data, UnitConverterUnits::Data_Kibibytes, 0.001024 }, - { ViewMode::Data, UnitConverterUnits::Data_Mebibits, 0.131072 }, - { ViewMode::Data, UnitConverterUnits::Data_Mebibytes, 1.048576 }, - { ViewMode::Data, UnitConverterUnits::Data_Pebibits, 140737488.355328 }, - { ViewMode::Data, UnitConverterUnits::Data_Pebibytes, 1125899906.842624 }, - { ViewMode::Data, UnitConverterUnits::Data_Tebibits, 137438.953472 }, - { ViewMode::Data, UnitConverterUnits::Data_Tebibytes, 1099511.627776 }, - { ViewMode::Data, UnitConverterUnits::Data_Exbibits, 144115188075.855872 }, - { ViewMode::Data, UnitConverterUnits::Data_Exbibytes, 1152921504606.846976 }, - { ViewMode::Data, UnitConverterUnits::Data_Zebibits, 147573952589676.412928 }, - { ViewMode::Data, UnitConverterUnits::Data_Zebibytes, 1180591620717411.303424 }, - { ViewMode::Data, UnitConverterUnits::Data_Yobibits, 151115727451828646.838272 }, - { ViewMode::Data, UnitConverterUnits::Data_Yobibytes, 1208925819614629174.706176 }, - { ViewMode::Data, UnitConverterUnits::Data_FloppyDisk, 1.509949 }, - { ViewMode::Data, UnitConverterUnits::Data_CD, 734.003200 }, - { ViewMode::Data, UnitConverterUnits::Data_DVD, 5046.586573 }, - - { ViewMode::Energy, UnitConverterUnits::Energy_Calorie, 4.184 }, - { ViewMode::Energy, UnitConverterUnits::Energy_Kilocalorie, 4184 }, - { ViewMode::Energy, UnitConverterUnits::Energy_BritishThermalUnit, 1055.056 }, - { ViewMode::Energy, UnitConverterUnits::Energy_Kilojoule, 1000 }, - { ViewMode::Energy, UnitConverterUnits::Energy_ElectronVolt, 0.0000000000000000001602176565 }, - { ViewMode::Energy, UnitConverterUnits::Energy_Joule, 1 }, - { ViewMode::Energy, UnitConverterUnits::Energy_FootPound, 1.3558179483314 }, - { ViewMode::Energy, UnitConverterUnits::Energy_Battery, 9000 }, - { ViewMode::Energy, UnitConverterUnits::Energy_Banana, 439614 }, - { ViewMode::Energy, UnitConverterUnits::Energy_SliceOfCake, 1046700 }, - - { ViewMode::Length, UnitConverterUnits::Length_Inch, 0.0254 }, - { ViewMode::Length, UnitConverterUnits::Length_Foot, 0.3048 }, - { ViewMode::Length, UnitConverterUnits::Length_Yard, 0.9144 }, - { ViewMode::Length, UnitConverterUnits::Length_Mile, 1609.344 }, - { ViewMode::Length, UnitConverterUnits::Length_Micron, 0.000001 }, - { ViewMode::Length, UnitConverterUnits::Length_Millimeter, 0.001 }, - { ViewMode::Length, UnitConverterUnits::Length_Nanometer, 0.000000001 }, - { ViewMode::Length, UnitConverterUnits::Length_Centimeter, 0.01 }, - { ViewMode::Length, UnitConverterUnits::Length_Meter, 1 }, - { ViewMode::Length, UnitConverterUnits::Length_Kilometer, 1000 }, - { ViewMode::Length, UnitConverterUnits::Length_NauticalMile, 1852 }, - { ViewMode::Length, UnitConverterUnits::Length_Paperclip, 0.035052 }, - { ViewMode::Length, UnitConverterUnits::Length_Hand, 0.18669 }, - { ViewMode::Length, UnitConverterUnits::Length_JumboJet, 76 }, - - { ViewMode::Power, UnitConverterUnits::Power_BritishThermalUnitPerMinute, 17.58426666666667 }, - { ViewMode::Power, UnitConverterUnits::Power_FootPoundPerMinute, 0.0225969658055233 }, - { ViewMode::Power, UnitConverterUnits::Power_Watt, 1 }, - { ViewMode::Power, UnitConverterUnits::Power_Kilowatt, 1000 }, - { ViewMode::Power, UnitConverterUnits::Power_Horsepower, 745.69987158227022 }, - { ViewMode::Power, UnitConverterUnits::Power_LightBulb, 60 }, - { ViewMode::Power, UnitConverterUnits::Power_Horse, 745.7 }, - { ViewMode::Power, UnitConverterUnits::Power_TrainEngine, 2982799.486329081 }, - - { ViewMode::Time, UnitConverterUnits::Time_Day, 86400 }, - { ViewMode::Time, UnitConverterUnits::Time_Second, 1 }, - { ViewMode::Time, UnitConverterUnits::Time_Week, 604800 }, - { ViewMode::Time, UnitConverterUnits::Time_Year, 31557600 }, - { ViewMode::Time, UnitConverterUnits::Time_Millisecond, 0.001 }, - { ViewMode::Time, UnitConverterUnits::Time_Microsecond, 0.000001 }, - { ViewMode::Time, UnitConverterUnits::Time_Minute, 60 }, - { ViewMode::Time, UnitConverterUnits::Time_Hour, 3600 }, - - { ViewMode::Volume, UnitConverterUnits::Volume_CupUS, 236.588237 }, - { ViewMode::Volume, UnitConverterUnits::Volume_PintUS, 473.176473 }, - { ViewMode::Volume, UnitConverterUnits::Volume_PintUK, 568.26125 }, - { ViewMode::Volume, UnitConverterUnits::Volume_QuartUS, 946.352946 }, - { ViewMode::Volume, UnitConverterUnits::Volume_QuartUK, 1136.5225 }, - { ViewMode::Volume, UnitConverterUnits::Volume_GallonUS, 3785.411784 }, - { ViewMode::Volume, UnitConverterUnits::Volume_GallonUK, 4546.09 }, - { ViewMode::Volume, UnitConverterUnits::Volume_Liter, 1000 }, - { ViewMode::Volume, UnitConverterUnits::Volume_TeaspoonUS, 4.92892159375 }, - { ViewMode::Volume, UnitConverterUnits::Volume_TablespoonUS, 14.78676478125 }, - { ViewMode::Volume, UnitConverterUnits::Volume_CubicCentimeter, 1 }, - { ViewMode::Volume, UnitConverterUnits::Volume_CubicYard, 764554.857984 }, - { ViewMode::Volume, UnitConverterUnits::Volume_CubicMeter, 1000000 }, - { ViewMode::Volume, UnitConverterUnits::Volume_Milliliter, 1 }, - { ViewMode::Volume, UnitConverterUnits::Volume_CubicInch, 16.387064 }, - { ViewMode::Volume, UnitConverterUnits::Volume_CubicFoot, 28316.846592 }, - { ViewMode::Volume, UnitConverterUnits::Volume_FluidOunceUS, 29.5735295625 }, - { ViewMode::Volume, UnitConverterUnits::Volume_FluidOunceUK, 28.4130625 }, - { ViewMode::Volume, UnitConverterUnits::Volume_TeaspoonUK, 5.91938802083333333333 }, - { ViewMode::Volume, UnitConverterUnits::Volume_TablespoonUK, 17.7581640625 }, - { ViewMode::Volume, UnitConverterUnits::Volume_CoffeeCup, 236.5882 }, - { ViewMode::Volume, UnitConverterUnits::Volume_Bathtub, 378541.2 }, - { ViewMode::Volume, UnitConverterUnits::Volume_SwimmingPool, 3750000000 }, - - { ViewMode::Weight, UnitConverterUnits::Weight_Kilogram, 1 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Hectogram, 0.1 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Decagram, 0.01 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Gram, 0.001 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Pound, 0.45359237 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Ounce, 0.028349523125 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Milligram, 0.000001 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Centigram, 0.00001 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Decigram, 0.0001 }, - { ViewMode::Weight, UnitConverterUnits::Weight_LongTon, 1016.0469088 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Tonne, 1000 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Stone, 6.35029318 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Carat, 0.0002 }, - { ViewMode::Weight, UnitConverterUnits::Weight_ShortTon, 907.18474 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Snowflake, 0.000002 }, - { ViewMode::Weight, UnitConverterUnits::Weight_SoccerBall, 0.4325 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Elephant, 4000 }, - { ViewMode::Weight, UnitConverterUnits::Weight_Whale, 90000 }, - - { ViewMode::Speed, UnitConverterUnits::Speed_CentimetersPerSecond, 1 }, - { ViewMode::Speed, UnitConverterUnits::Speed_FeetPerSecond, 30.48 }, - { ViewMode::Speed, UnitConverterUnits::Speed_KilometersPerHour, 27.777777777777777777778 }, - { ViewMode::Speed, UnitConverterUnits::Speed_Knot, 51.44 }, - { ViewMode::Speed, UnitConverterUnits::Speed_Mach, 34030 }, - { ViewMode::Speed, UnitConverterUnits::Speed_MetersPerSecond, 100 }, - { ViewMode::Speed, UnitConverterUnits::Speed_MilesPerHour, 44.7 }, - { ViewMode::Speed, UnitConverterUnits::Speed_Turtle, 8.94 }, - { ViewMode::Speed, UnitConverterUnits::Speed_Horse, 2011.5 }, - { ViewMode::Speed, UnitConverterUnits::Speed_Jet, 24585 }, - - { ViewMode::Angle, UnitConverterUnits::Angle_Degree, 1 }, - { ViewMode::Angle, UnitConverterUnits::Angle_Radian, 57.29577951308233 }, - { ViewMode::Angle, UnitConverterUnits::Angle_Gradian, 0.9 }, - - { ViewMode::Pressure, UnitConverterUnits::Pressure_Atmosphere, 1 }, - { ViewMode::Pressure, UnitConverterUnits::Pressure_Bar, 0.9869232667160128 }, - { ViewMode::Pressure, UnitConverterUnits::Pressure_KiloPascal, 0.0098692326671601 }, - { ViewMode::Pressure, UnitConverterUnits::Pressure_MillimeterOfMercury, 0.0013155687145324 }, - { ViewMode::Pressure, UnitConverterUnits::Pressure_Pascal, 9.869232667160128e-6 }, - { ViewMode::Pressure, UnitConverterUnits::Pressure_PSI, 0.068045961016531 } }; - - // Populate the hash map and return; - for (UnitData unitdata : unitDataList) - { - if (categoryToUnitConversionMap.find(unitdata.categoryId) == categoryToUnitConversionMap.end()) - { - unordered_map conversionData; - conversionData.insert(pair(unitdata.unitId, unitdata.factor)); - categoryToUnitConversionMap.insert(pair>(unitdata.categoryId, conversionData)); - } - else - { - categoryToUnitConversionMap.at(unitdata.categoryId).insert(pair(unitdata.unitId, unitdata.factor)); - } - } -} - -wstring UnitConverterDataLoader::GetLocalizedStringName(String ^ stringId) -{ - return AppResourceProvider::GetInstance().GetResourceString(stringId)->Data(); -} - -void UnitConverterDataLoader::GetExplicitConversionData(_In_ unordered_map>& unitToUnitConversionList) -{ - /* categoryId, ParentUnitId, UnitId, ratio, offset, offsetfirst*/ - ExplicitUnitConversionData conversionDataList[] = { - { ViewMode::Temperature, UnitConverterUnits::Temperature_DegreesCelsius, UnitConverterUnits::Temperature_DegreesCelsius, 1, 0 }, - { ViewMode::Temperature, UnitConverterUnits::Temperature_DegreesCelsius, UnitConverterUnits::Temperature_DegreesFahrenheit, 1.8, 32 }, - { ViewMode::Temperature, UnitConverterUnits::Temperature_DegreesCelsius, UnitConverterUnits::Temperature_Kelvin, 1, 273.15 }, - { ViewMode::Temperature, - UnitConverterUnits::Temperature_DegreesFahrenheit, - UnitConverterUnits::Temperature_DegreesCelsius, - 0.55555555555555555555555555555556, - -32, - CONVERT_WITH_OFFSET_FIRST }, - { ViewMode::Temperature, UnitConverterUnits::Temperature_DegreesFahrenheit, UnitConverterUnits::Temperature_DegreesFahrenheit, 1, 0 }, - { ViewMode::Temperature, - UnitConverterUnits::Temperature_DegreesFahrenheit, - UnitConverterUnits::Temperature_Kelvin, - 0.55555555555555555555555555555556, - 459.67, - CONVERT_WITH_OFFSET_FIRST }, - { ViewMode::Temperature, - UnitConverterUnits::Temperature_Kelvin, - UnitConverterUnits::Temperature_DegreesCelsius, - 1, - -273.15, - CONVERT_WITH_OFFSET_FIRST }, - { ViewMode::Temperature, UnitConverterUnits::Temperature_Kelvin, UnitConverterUnits::Temperature_DegreesFahrenheit, 1.8, -459.67 }, - { ViewMode::Temperature, UnitConverterUnits::Temperature_Kelvin, UnitConverterUnits::Temperature_Kelvin, 1, 0 } - }; - - // Populate the hash map and return; - for (ExplicitUnitConversionData data : conversionDataList) - { - if (unitToUnitConversionList.find(data.parentUnitId) == unitToUnitConversionList.end()) - { - unordered_map conversionData; - conversionData.insert(pair(data.unitId, static_cast(data))); - unitToUnitConversionList.insert(pair>(data.parentUnitId, conversionData)); - } - else - { - unitToUnitConversionList.at(data.parentUnitId).insert(pair(data.unitId, static_cast(data))); - } - } -} diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.h b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.h deleted file mode 100644 index 58d78e28..00000000 --- a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/UnitConverter.h" -#include "Common/NavCategory.h" - -namespace CalculatorApp -{ - namespace ViewModel - { - struct OrderedUnit : UnitConversionManager::Unit - { - OrderedUnit() - { - } - - OrderedUnit( - int id, - std::wstring name, - std::wstring abbreviation, - int order, - bool isConversionSource = false, - bool isConversionTarget = false, - bool isWhimsical = false) - : UnitConversionManager::Unit(id, name, abbreviation, isConversionSource, isConversionTarget, isWhimsical) - , order(order) - { - } - - int order; - }; - - struct UnitData - { - CalculatorApp::Common::ViewMode categoryId; - int unitId; - double factor; - }; - - struct ExplicitUnitConversionData : UnitConversionManager::ConversionData - { - ExplicitUnitConversionData() - { - } - ExplicitUnitConversionData( - CalculatorApp::Common::ViewMode categoryId, - int parentUnitId, - int unitId, - double ratio, - double offset, - bool offsetFirst = false) - : categoryId(categoryId) - , parentUnitId(parentUnitId) - , unitId(unitId) - , UnitConversionManager::ConversionData(ratio, offset, offsetFirst) - { - } - - CalculatorApp::Common::ViewMode categoryId; - int parentUnitId; - int unitId; - }; - - class UnitConverterDataLoader : public UnitConversionManager::IConverterDataLoader, public std::enable_shared_from_this - { - public: - UnitConverterDataLoader(Windows::Globalization::GeographicRegion ^ region); - - private: - // IConverterDataLoader - void LoadData() override; - std::vector LoadOrderedCategories() override; - std::vector LoadOrderedUnits(const UnitConversionManager::Category& c) override; - std::unordered_map - LoadOrderedRatios(const UnitConversionManager::Unit& unit) override; - bool SupportsCategory(const UnitConversionManager::Category& target) override; - // IConverterDataLoader - - void GetCategories(_In_ std::shared_ptr> categoriesList); - void GetUnits(_In_ std::unordered_map>& unitMap); - void GetConversionData(_In_ std::unordered_map>& categoryToUnitConversionMap); - void - GetExplicitConversionData(_In_ std::unordered_map>& unitToUnitConversionList); - - std::wstring GetLocalizedStringName(_In_ Platform::String ^ stringId); - - std::shared_ptr> m_categoryList; - std::shared_ptr m_categoryToUnits; - std::shared_ptr m_ratioMap; - Platform::String ^ m_currentRegionCode; - }; - } -} diff --git a/src/CalcViewModel/DateCalculatorViewModel.cpp b/src/CalcViewModel/DateCalculatorViewModel.cpp deleted file mode 100644 index 164a9281..00000000 --- a/src/CalcViewModel/DateCalculatorViewModel.cpp +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "DateCalculatorViewModel.h" -#include "Common/TraceLogger.h" -#include "Common/LocalizationStringUtil.h" -#include "Common/LocalizationService.h" -#include "Common/LocalizationSettings.h" -#include "Common/CopyPasteManager.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::DateCalculation; -using namespace CalculatorApp::ViewModel; -using namespace Platform; -using namespace Platform::Collections; -using namespace std; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::Foundation; -using namespace Windows::Globalization; -using namespace Windows::Globalization::DateTimeFormatting; -using namespace Windows::System::UserProfile; - -namespace -{ - StringReference StrDateDiffResultPropertyName(L"StrDateDiffResult"); - StringReference StrDateDiffResultAutomationNamePropertyName(L"StrDateDiffResultAutomationName"); - StringReference StrDateDiffResultInDaysPropertyName(L"StrDateDiffResultInDays"); - StringReference StrDateResultPropertyName(L"StrDateResult"); - StringReference StrDateResultAutomationNamePropertyName(L"StrDateResultAutomationName"); - StringReference IsDiffInDaysPropertyName(L"IsDiffInDays"); -} - -DateCalculatorViewModel::DateCalculatorViewModel() - : m_IsDateDiffMode(true) - , m_IsAddMode(true) - , m_isOutOfBound(false) - , m_DaysOffset(0) - , m_MonthsOffset(0) - , m_YearsOffset(0) - , m_StrDateDiffResult(L"") - , m_StrDateDiffResultAutomationName(L"") - , m_StrDateDiffResultInDays(L"") - , m_StrDateResult(L"") - , m_StrDateResultAutomationName(L"") -{ - const auto& localizationSettings = LocalizationSettings::GetInstance(); - - // Initialize Date Output format instances - InitializeDateOutputFormats(localizationSettings.GetCalendarIdentifier()); - - // Initialize Date Calc engine - m_dateCalcEngine = make_shared(localizationSettings.GetCalendarIdentifier()); - // Initialize dates of DatePicker controls to today's date - auto calendar = ref new Calendar(); - // We force the timezone to UTC, in order to avoid being affected by Daylight Saving Time - // when we calculate the difference between 2 dates. - calendar->ChangeTimeZone("UTC"); - auto today = calendar->GetDateTime(); - - // FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC) - m_fromDate = ClipTime(today); - m_toDate = ClipTime(today); - - // StartDate should not be clipped - m_startDate = today; - m_dateResult = today; - - // Initialize the list separator delimiter appended with a space at the end, e.g. ", " - // This will be used for date difference formatting: Y years, M months, W weeks, D days - m_listSeparator = localizationSettings.GetListSeparator() + L" "; - - // Initialize the output results - UpdateDisplayResult(); - - m_offsetValues = ref new Vector(); - for (int i = 0; i <= c_maxOffsetValue; i++) - { - wstring numberStr(to_wstring(i)); - localizationSettings.LocalizeDisplayValue(&numberStr); - m_offsetValues->Append(ref new String(numberStr.c_str())); - } - - DayOfWeek trueDayOfWeek = calendar->DayOfWeek; - - DateTime clippedTime = ClipTime(today); - calendar->SetDateTime(clippedTime); - if (calendar->DayOfWeek != trueDayOfWeek) - { - calendar->SetDateTime(today); - TraceLogger::GetInstance().LogDateClippedTimeDifferenceFound( - from_cx(calendar), - winrt::Windows::Foundation::DateTime{ winrt::Windows::Foundation::TimeSpan{ clippedTime.UniversalTime } }); - } -} - -void DateCalculatorViewModel::OnPropertyChanged(_In_ String ^ prop) -{ - if (prop == StrDateDiffResultPropertyName) - { - UpdateStrDateDiffResultAutomationName(); - } - else if (prop == StrDateResultPropertyName) - { - UpdateStrDateResultAutomationName(); - } - else if ( - prop != StrDateDiffResultAutomationNamePropertyName && prop != StrDateDiffResultInDaysPropertyName && prop != StrDateResultAutomationNamePropertyName - && prop != IsDiffInDaysPropertyName) - { - OnInputsChanged(); - } -} - -void DateCalculatorViewModel::OnInputsChanged() -{ - DateDifference dateDiff; - - if (m_IsDateDiffMode) - { - DateTime clippedFromDate = ClipTime(FromDate); - DateTime clippedToDate = ClipTime(ToDate); - - // Calculate difference between two dates - m_dateCalcEngine->GetDateDifference(clippedFromDate, clippedToDate, m_allDateUnitsOutputFormat, &dateDiff); - DateDiffResult = dateDiff; - - m_dateCalcEngine->GetDateDifference(clippedFromDate, clippedToDate, m_daysOutputFormat, &dateDiff); - DateDiffResultInDays = dateDiff; - } - else - { - dateDiff.day = DaysOffset; - dateDiff.month = MonthsOffset; - dateDiff.year = YearsOffset; - - DateTime dateTimeResult; - - if (m_IsAddMode) - { - // Add number of Days, Months and Years to a Date - IsOutOfBound = !m_dateCalcEngine->AddDuration(StartDate, dateDiff, &dateTimeResult); - } - else - { - // Subtract number of Days, Months and Years from a Date - IsOutOfBound = !m_dateCalcEngine->SubtractDuration(StartDate, dateDiff, &dateTimeResult); - } - - if (!m_isOutOfBound) - { - DateResult = dateTimeResult; - } - } -} - -void DateCalculatorViewModel::UpdateDisplayResult() -{ - if (m_IsDateDiffMode) - { - // Are to and from dates the same - if (m_dateDiffResultInDays.day == 0) - { - IsDiffInDays = true; - StrDateDiffResultInDays = L""; - StrDateDiffResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_SameDates"); - } - else if ((m_dateDiffResult.year == 0) && (m_dateDiffResult.month == 0) && (m_dateDiffResult.week == 0)) - { - IsDiffInDays = true; - StrDateDiffResultInDays = L""; - - // Display result in number of days - StrDateDiffResult = GetDateDiffStringInDays(); - } - else - { - IsDiffInDays = false; - - // Display result in days, weeks, months and years - StrDateDiffResult = GetDateDiffString(); - - // Display result in number of days - StrDateDiffResultInDays = GetDateDiffStringInDays(); - } - } - else - { - if (m_isOutOfBound) - { - // Display Date out of bound message - StrDateResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_OutOfBoundMessage"); - } - else - { - // Display the resulting date in long format - StrDateResult = m_dateTimeFormatter->Format(DateResult); - } - } -} - -void DateCalculatorViewModel::UpdateStrDateDiffResultAutomationName() -{ - String ^ automationFormat = AppResourceProvider::GetInstance().GetResourceString(L"Date_DifferenceResultAutomationName"); - wstring localizedAutomationName = LocalizationStringUtil::GetLocalizedString(automationFormat->Data(), StrDateDiffResult->Data()); - StrDateDiffResultAutomationName = ref new String(localizedAutomationName.c_str()); -} - -void DateCalculatorViewModel::UpdateStrDateResultAutomationName() -{ - String ^ automationFormat = AppResourceProvider::GetInstance().GetResourceString(L"Date_ResultingDateAutomationName"); - wstring localizedAutomationName = LocalizationStringUtil::GetLocalizedString(automationFormat->Data(), StrDateResult->Data()); - StrDateResultAutomationName = ref new String(localizedAutomationName.c_str()); -} - -void DateCalculatorViewModel::InitializeDateOutputFormats(_In_ String ^ calendarIdentifier) -{ - // Format for Add/Subtract days - m_dateTimeFormatter = LocalizationService::GetRegionalSettingsAwareDateTimeFormatter( - L"longdate", - calendarIdentifier, - ClockIdentifiers::TwentyFourHour); // Clock Identifier is not used - - // Format for Date Difference - m_allDateUnitsOutputFormat = DateUnit::Year | DateUnit::Month | DateUnit::Week | DateUnit::Day; - m_daysOutputFormat = DateUnit::Day; -} - -String ^ DateCalculatorViewModel::GetDateDiffString() const -{ - wstring result; - bool addDelimiter = false; - AppResourceProvider resourceLoader = AppResourceProvider::GetInstance(); - - auto yearCount = m_dateDiffResult.year; - if (yearCount > 0) - { - result += GetLocalizedNumberString(yearCount)->Data(); - result += L" "; - - if (yearCount > 1) - { - result += resourceLoader.GetResourceString(L"Date_Years")->Data(); - } - else - { - result += resourceLoader.GetResourceString(L"Date_Year")->Data(); - } - - // set the flags to add a delimiter whenever the next unit is added - addDelimiter = true; - } - - auto monthCount = m_dateDiffResult.month; - if (monthCount > 0) - { - if (addDelimiter) - { - result += m_listSeparator; - } - else - { - addDelimiter = true; - } - - result += GetLocalizedNumberString(monthCount)->Data(); - result += L" "; - - if (monthCount > 1) - { - result += resourceLoader.GetResourceString(L"Date_Months")->Data(); - } - else - { - result += resourceLoader.GetResourceString(L"Date_Month")->Data(); - } - } - - auto weekCount = m_dateDiffResult.week; - if (weekCount > 0) - { - if (addDelimiter) - { - result += m_listSeparator; - } - else - { - addDelimiter = true; - } - - result += GetLocalizedNumberString(weekCount)->Data(); - result += L" "; - - if (weekCount > 1) - { - result += resourceLoader.GetResourceString(L"Date_Weeks")->Data(); - } - else - { - result += resourceLoader.GetResourceString(L"Date_Week")->Data(); - } - } - - auto dayCount = m_dateDiffResult.day; - if (dayCount > 0) - { - if (addDelimiter) - { - result += m_listSeparator; - } - else - { - addDelimiter = true; - } - - result += GetLocalizedNumberString(dayCount)->Data(); - result += L" "; - - if (dayCount > 1) - { - result += resourceLoader.GetResourceString(L"Date_Days")->Data(); - } - else - { - result += resourceLoader.GetResourceString(L"Date_Day")->Data(); - } - } - - return ref new String(result.data()); -} - -String ^ DateCalculatorViewModel::GetDateDiffStringInDays() const -{ - wstring result = GetLocalizedNumberString(m_dateDiffResultInDays.day)->Data(); - result += L" "; - - // Display the result as '1 day' or 'N days' - if (m_dateDiffResultInDays.day > 1) - { - result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Days")->Data(); - } - else - { - result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Day")->Data(); - } - - return ref new String(result.data()); -} - -void DateCalculatorViewModel::OnCopyCommand(Platform::Object ^ parameter) -{ - if (m_IsDateDiffMode) - { - CopyPasteManager::CopyToClipboard(m_StrDateDiffResult); - } - else - { - CopyPasteManager::CopyToClipboard(m_StrDateResult); - } -} - -String ^ DateCalculatorViewModel::GetLocalizedNumberString(int value) const -{ - wstring numberStr(to_wstring(value)); - LocalizationSettings::GetInstance().LocalizeDisplayValue(&numberStr); - return ref new String(numberStr.c_str()); -} - -// Adjusts the given DateTime to 12AM (UTC) of the same day -DateTime DateCalculatorViewModel::ClipTime(DateTime dateTime) -{ - auto calendar = ref new Calendar(); - calendar->ChangeTimeZone("UTC"); - calendar->SetDateTime(dateTime); - calendar->Period = calendar->FirstPeriodInThisDay; - calendar->Hour = calendar->FirstHourInThisPeriod; - calendar->Minute = 0; - calendar->Second = 0; - calendar->Nanosecond = 0; - - return calendar->GetDateTime(); -} diff --git a/src/CalcViewModel/DateCalculatorViewModel.h b/src/CalcViewModel/DateCalculatorViewModel.h deleted file mode 100644 index 9423a105..00000000 --- a/src/CalcViewModel/DateCalculatorViewModel.h +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "Common/Utils.h" -#include "Common/DateCalculator.h" - -const int c_maxOffsetValue = 999; - -namespace CalculatorApp -{ - namespace ViewModel - { - [Windows::UI::Xaml::Data::Bindable] public ref class DateCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - public: - DateCalculatorViewModel(); - - OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); - - // Input Properties - OBSERVABLE_PROPERTY_RW(bool, IsDateDiffMode); - OBSERVABLE_PROPERTY_RW(bool, IsAddMode); - OBSERVABLE_PROPERTY_R(bool, IsDiffInDays); // If diff is only in days or the dates are the same, - // then show only one result and avoid redundancy - - OBSERVABLE_PROPERTY_RW(int, DaysOffset); - OBSERVABLE_PROPERTY_RW(int, MonthsOffset); - OBSERVABLE_PROPERTY_RW(int, YearsOffset); - - // Read only property for offset values - property Windows::Foundation::Collections::IVector^ OffsetValues - { - Windows::Foundation::Collections::IVector^ get() { return m_offsetValues; } - } - - // From date for Date Diff - property Windows::Foundation::DateTime FromDate - { - Windows::Foundation::DateTime get() - { - return m_fromDate; - } - - void set(Windows::Foundation::DateTime value) - { - if (m_fromDate.UniversalTime != value.UniversalTime) - { - m_fromDate = value; - RaisePropertyChanged("FromDate"); - } - } - } - - // To date for Date Diff - property Windows::Foundation::DateTime ToDate - { - Windows::Foundation::DateTime get() - { - return m_toDate; - } - - void set(Windows::Foundation::DateTime value) - { - if (m_toDate.UniversalTime != value.UniversalTime) - { - m_toDate = value; - RaisePropertyChanged("ToDate"); - } - } - } - - // Start date for Add/Subtract date - property Windows::Foundation::DateTime StartDate - { - Windows::Foundation::DateTime get() - { - return m_startDate; - } - - void set(Windows::Foundation::DateTime value) - { - if (m_startDate.UniversalTime != value.UniversalTime) - { - m_startDate = value; - RaisePropertyChanged("StartDate"); - } - } - } - - // Output Properties - OBSERVABLE_PROPERTY_R(Platform::String ^, StrDateDiffResult); - OBSERVABLE_PROPERTY_R(Platform::String ^, StrDateDiffResultAutomationName); - OBSERVABLE_PROPERTY_R(Platform::String ^, StrDateDiffResultInDays); - OBSERVABLE_PROPERTY_R(Platform::String ^, StrDateResult); - OBSERVABLE_PROPERTY_R(Platform::String ^, StrDateResultAutomationName); - - COMMAND_FOR_METHOD(CopyCommand, DateCalculatorViewModel::OnCopyCommand); - - void OnCopyCommand(Platform::Object ^ parameter); - - private: - void OnPropertyChanged(_In_ Platform::String ^ prop); - void OnInputsChanged(); - void UpdateDisplayResult(); - void UpdateStrDateDiffResultAutomationName(); - void UpdateStrDateResultAutomationName(); - void InitializeDateOutputFormats(Platform::String ^ calendarIdentifier); - Platform::String ^ GetDateDiffString() const; - Platform::String ^ GetDateDiffStringInDays() const; - Platform::String ^ GetLocalizedNumberString(int value) const; - static Windows::Foundation::DateTime ClipTime(Windows::Foundation::DateTime dateTime); - - property bool IsOutOfBound - { - bool get() - { - return m_isOutOfBound; - } - void set(bool value) - { - m_isOutOfBound = value; - UpdateDisplayResult(); - } - } - - property CalculatorApp::Common::DateCalculation::DateDifference DateDiffResult - { - CalculatorApp::Common::DateCalculation::DateDifference get() - { - return m_dateDiffResult; - } - void set(CalculatorApp::Common::DateCalculation::DateDifference value) - { - m_dateDiffResult = value; - UpdateDisplayResult(); - } - } - - property CalculatorApp::Common::DateCalculation::DateDifference DateDiffResultInDays - { - CalculatorApp::Common::DateCalculation::DateDifference get() - { - return m_dateDiffResultInDays; - } - void set(CalculatorApp::Common::DateCalculation::DateDifference value) - { - m_dateDiffResultInDays = value; - UpdateDisplayResult(); - } - } - - property Windows::Foundation::DateTime DateResult - { - Windows::Foundation::DateTime get() - { - return m_dateResult; - } - void set(Windows::Foundation::DateTime value) - { - m_dateResult = value; - UpdateDisplayResult(); - } - } - - private: - // Property variables - bool m_isOutOfBound; - Platform::Collections::Vector ^ m_offsetValues; - Windows::Foundation::DateTime m_fromDate; - Windows::Foundation::DateTime m_toDate; - Windows::Foundation::DateTime m_startDate; - Windows::Foundation::DateTime m_dateResult; - CalculatorApp::Common::DateCalculation::DateDifference m_dateDiffResult; - CalculatorApp::Common::DateCalculation::DateDifference m_dateDiffResultInDays; - - // Private members - std::shared_ptr m_dateCalcEngine; - CalculatorApp::Common::DateCalculation::DateUnit m_daysOutputFormat; - CalculatorApp::Common::DateCalculation::DateUnit m_allDateUnitsOutputFormat; - Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ m_dateTimeFormatter; - std::wstring m_listSeparator; - }; - } -} diff --git a/src/CalcViewModel/HistoryItemViewModel.cpp b/src/CalcViewModel/HistoryItemViewModel.cpp deleted file mode 100644 index 63d5e966..00000000 --- a/src/CalcViewModel/HistoryItemViewModel.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "HistoryItemViewModel.h" -#include "Common/LocalizationService.h" - -using namespace CalculatorApp::Common; -using namespace CalculatorApp::ViewModel; -using namespace std; -using namespace Platform; - -HistoryItemViewModel::HistoryItemViewModel( - String ^ expression, - String ^ result, - _In_ const shared_ptr>>& spTokens, - _In_ const shared_ptr>>& spCommands) - : m_expression(expression) - , m_result(result) - , m_spTokens(spTokens) - , m_spCommands(spCommands) -{ - // updating accessibility names for expression and result - m_accExpression = HistoryItemViewModel::GetAccessibleExpressionFromTokens(spTokens, m_expression); - m_accResult = LocalizationService::GetNarratorReadableString(m_result); -} - -String - ^ HistoryItemViewModel::GetAccessibleExpressionFromTokens( - _In_ shared_ptr>> const& spTokens, - _In_ String ^ fallbackExpression) -{ - // updating accessibility names for expression and result - wstringstream accExpression{}; - accExpression << L""; - - unsigned int nTokens; - HRESULT hr = spTokens->GetSize(&nTokens); - if (SUCCEEDED(hr)) - { - pair tokenItem; - for (unsigned int i = 0; i < nTokens; i++) - { - hr = spTokens->GetAt(i, &tokenItem); - if (FAILED(hr)) - { - break; - } - - wstring token = tokenItem.first; - accExpression << LocalizationService::GetNarratorReadableToken(StringReference(token.c_str()))->Data(); - } - } - - if (SUCCEEDED(hr)) - { - wstring expressionSuffix{}; - hr = spTokens->GetExpressionSuffix(&expressionSuffix); - if (SUCCEEDED(hr)) - { - accExpression << expressionSuffix; - } - } - - if (FAILED(hr)) - { - return LocalizationService::GetNarratorReadableString(fallbackExpression); - } - else - { - return ref new String(accExpression.str().c_str()); - } -} diff --git a/src/CalcViewModel/HistoryItemViewModel.h b/src/CalcViewModel/HistoryItemViewModel.h deleted file mode 100644 index fae51e69..00000000 --- a/src/CalcViewModel/HistoryItemViewModel.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/CalculatorVector.h" -#include "CalcManager/ExpressionCommandInterface.h" - -namespace CalculatorApp -{ - namespace ViewModel - { - [Windows::UI::Xaml::Data::Bindable] public ref class HistoryItemViewModel sealed : Windows::UI::Xaml::Data::ICustomPropertyProvider - { - internal : - - HistoryItemViewModel( - Platform::String ^ expression, - Platform::String ^ result, - _In_ std::shared_ptr>> const& spTokens, - _In_ std::shared_ptr>> const& spCommands); - - std::shared_ptr>> const& GetTokens() - { - return m_spTokens; - } - - std::shared_ptr>> const& GetCommands() - { - return m_spCommands; - } - - public: - property Platform::String - ^ Expression { Platform::String ^ get() { return m_expression; } } - - property Platform::String - ^ AccExpression { Platform::String ^ get() { return m_accExpression; } } - - property Platform::String - ^ Result { Platform::String ^ get() { return m_result; } } - - property Platform::String - ^ AccResult { Platform::String ^ get() { return m_accResult; } } - - virtual Windows::UI::Xaml::Data::ICustomProperty - ^ GetCustomProperty(Platform::String ^ name) { return nullptr; } - - virtual Windows::UI::Xaml::Data::ICustomProperty - ^ GetIndexedProperty(Platform::String ^ name, Windows::UI::Xaml::Interop::TypeName type) { return nullptr; } - - virtual property Windows::UI::Xaml::Interop::TypeName Type - { - Windows::UI::Xaml::Interop::TypeName get() - { - return this->GetType(); - } - } - - virtual Platform::String - ^ GetStringRepresentation() { return m_accExpression + " " + m_accResult; } - - private : static Platform::String - ^ GetAccessibleExpressionFromTokens( - _In_ std::shared_ptr>> const& spTokens, - _In_ Platform::String ^ fallbackExpression); - - private: - Platform::String ^ m_expression; - Platform::String ^ m_accExpression; - Platform::String ^ m_accResult; - Platform::String ^ m_result; - std::shared_ptr>> m_spTokens; - std::shared_ptr>> m_spCommands; - }; - } -} diff --git a/src/CalcViewModel/HistoryViewModel.cpp b/src/CalcViewModel/HistoryViewModel.cpp deleted file mode 100644 index 70374252..00000000 --- a/src/CalcViewModel/HistoryViewModel.cpp +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "HistoryViewModel.h" -#include "Common/TraceLogger.h" -#include "Common/LocalizationStringUtil.h" -#include "Common/LocalizationSettings.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::Automation; -using namespace CalculatorApp::ViewModel; -using namespace Platform; -using namespace std; -using namespace Windows::Foundation; -using namespace Windows::Storage; -using namespace Windows::Storage::Streams; -using namespace Windows::Security::Cryptography; -using namespace Windows::Foundation::Collections; - -static StringReference HistoryVectorLengthKey{ L"HistoryVectorLength" }; - -namespace CalculatorApp::ViewModel::HistoryResourceKeys -{ - StringReference HistoryCleared(L"HistoryList_Cleared"); -} - -HistoryViewModel::HistoryViewModel(_In_ CalculationManager::CalculatorManager* calculatorManager) - : m_calculatorManager(calculatorManager) - , m_localizedHistoryCleared(nullptr) -{ - AreHistoryShortcutsEnabled = true; - - Items = ref new Platform::Collections::Vector(); - ItemSize = 0; -} - -void HistoryViewModel::RestoreCompleteHistory() -{ - RestoreHistory(CalculationManager::CALCULATOR_MODE::CM_STD); - RestoreHistory(CalculationManager::CALCULATOR_MODE::CM_SCI); -} - -// this will reload Items with the history list based on current mode -void HistoryViewModel::ReloadHistory(_In_ ViewMode currentMode) -{ - if (currentMode == ViewMode::Standard) - { - m_currentMode = CalculationManager::CALCULATOR_MODE::CM_STD; - } - else if (currentMode == ViewMode::Scientific) - { - m_currentMode = CalculationManager::CALCULATOR_MODE::CM_SCI; - } - else - { - return; - } - - auto historyListModel = m_calculatorManager->GetHistoryItems(m_currentMode); - auto historyListVM = ref new Platform::Collections::Vector(); - const auto& localizer = LocalizationSettings::GetInstance(); - if (historyListModel.size() > 0) - { - for (auto ritr = historyListModel.rbegin(); ritr != historyListModel.rend(); ++ritr) - { - wstring expression = (*ritr)->historyItemVector.expression; - wstring result = (*ritr)->historyItemVector.result; - localizer.LocalizeDisplayValue(&expression); - localizer.LocalizeDisplayValue(&result); - - auto item = ref new HistoryItemViewModel( - ref new Platform::String(expression.c_str()), - ref new Platform::String(result.c_str()), - (*ritr)->historyItemVector.spTokens, - (*ritr)->historyItemVector.spCommands); - historyListVM->Append(item); - } - } - - Items = historyListVM; - UpdateItemSize(); -} - -void HistoryViewModel::OnHistoryItemAdded(_In_ unsigned int addedItemIndex) -{ - auto newItem = m_calculatorManager->GetHistoryItem(addedItemIndex); - const auto& localizer = LocalizationSettings::GetInstance(); - wstring expression = newItem->historyItemVector.expression; - wstring result = newItem->historyItemVector.result; - localizer.LocalizeDisplayValue(&expression); - localizer.LocalizeDisplayValue(&result); - auto item = ref new HistoryItemViewModel( - ref new Platform::String(expression.c_str()), - ref new Platform::String(result.c_str()), - newItem->historyItemVector.spTokens, - newItem->historyItemVector.spCommands); - - // check if we have not hit the max items - if (Items->Size >= m_calculatorManager->MaxHistorySize()) - { - // this means the item already exists - Items->RemoveAt(Items->Size - 1); - } - - assert(addedItemIndex <= m_calculatorManager->MaxHistorySize() && addedItemIndex >= 0); - Items->InsertAt(0, item); - UpdateItemSize(); - SaveHistory(); -} - -void HistoryViewModel::SetCalculatorDisplay(CalculatorDisplay& calculatorDisplay) -{ - WeakReference historyViewModel(this); - calculatorDisplay.SetHistoryCallback(historyViewModel); -} - -void HistoryViewModel::ShowItem(_In_ HistoryItemViewModel ^ e) -{ - HistoryItemClicked(e); -} - -void HistoryViewModel::DeleteItem(_In_ HistoryItemViewModel ^ e) -{ - uint32_t itemIndex; - if (Items->IndexOf(e, &itemIndex)) - { - if (m_calculatorManager->RemoveHistoryItem(itemIndex)) - { - // Keys for the history container are index based. - // SaveHistory() re-inserts the items anyway, so it's faster to just clear out the container. - CalculationManager::CALCULATOR_MODE currentMode = m_currentMode; - ApplicationDataContainer ^ historyContainer = GetHistoryContainer(currentMode); - historyContainer->Values->Clear(); - - Items->RemoveAt(itemIndex); - UpdateItemSize(); - SaveHistory(); - } - } -} - -void HistoryViewModel::OnHideCommand(_In_ Platform::Object ^ e) -{ - // added at VM layer so that the views do not have to individually raise events - HideHistoryClicked(); -} - -void HistoryViewModel::OnClearCommand(_In_ Platform::Object ^ e) -{ - TraceLogger::GetInstance().LogClearHistory(); - if (AreHistoryShortcutsEnabled == true) - { - m_calculatorManager->ClearHistory(); - - if (Items->Size > 0) - { - CalculationManager::CALCULATOR_MODE currentMode = m_currentMode; - ClearHistoryContainer(currentMode); - Items->Clear(); - UpdateItemSize(); - } - - MakeHistoryClearedNarratorAnnouncement(HistoryResourceKeys::HistoryCleared, m_localizedHistoryCleared); - } -} - -// this method restores history vector per mode -void HistoryViewModel::RestoreHistory(_In_ CalculationManager::CALCULATOR_MODE cMode) -{ - ApplicationDataContainer ^ historyContainer = GetHistoryContainer(cMode); - std::shared_ptr>> historyVector = - std::make_shared>>(); - auto historyVectorLength = static_cast(historyContainer->Values->Lookup(HistoryVectorLengthKey)); - bool failure = false; - - if (historyVectorLength > 0) - { - for (int i = 0; i < historyVectorLength; ++i) - { - try - { - // deserialize each item - auto item = DeserializeHistoryItem(i.ToString(), historyContainer); - std::shared_ptr Item = std::make_shared(item); - historyVector->push_back(Item); - } - catch (Platform::Exception ^ e) - { - failure = true; - break; - } - } - - if (!failure) - { - // if task has been cancelled set history to 0 - m_calculatorManager->SetHistory(cMode, *historyVector); - - // update length once again for consistency between stored number of items and length - UpdateHistoryVectorLength(static_cast(historyVector->size()), cMode); - } - else - { - // in case of failure do not show any item - UpdateHistoryVectorLength(0, cMode); - } - } -} - -Platform::String ^ HistoryViewModel::GetHistoryContainerKey(_In_ CalculationManager::CALCULATOR_MODE cMode) -{ - Platform::ValueType ^ modeValue = static_cast(cMode); - return Platform::String::Concat(modeValue->ToString(), L"_History"); -} - -ApplicationDataContainer ^ HistoryViewModel::GetHistoryContainer(_In_ CalculationManager::CALCULATOR_MODE cMode) -{ - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - ApplicationDataContainer ^ historyContainer; - - // naming container based on mode - Platform::String ^ historyContainerKey = GetHistoryContainerKey(cMode); - - if (localSettings->Containers->HasKey(historyContainerKey)) - { - historyContainer = localSettings->Containers->Lookup(historyContainerKey); - } - else - { - // create container for adding data - historyContainer = localSettings->CreateContainer(historyContainerKey, ApplicationDataCreateDisposition::Always); - int initialHistoryVectorLength = 0; - historyContainer->Values->Insert(HistoryVectorLengthKey, initialHistoryVectorLength); - } - - return historyContainer; -} - -void HistoryViewModel::ClearHistoryContainer(_In_ CalculationManager::CALCULATOR_MODE cMode) -{ - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - localSettings->DeleteContainer(GetHistoryContainerKey(cMode)); -} - -// this method will be used to update the history item length -void HistoryViewModel::UpdateHistoryVectorLength(_In_ int newValue, _In_ CalculationManager::CALCULATOR_MODE cMode) -{ - ApplicationDataContainer ^ historyContainer = GetHistoryContainer(cMode); - historyContainer->Values->Remove(HistoryVectorLengthKey); - historyContainer->Values->Insert(HistoryVectorLengthKey, newValue); -} - -void HistoryViewModel::ClearHistory() -{ - ClearHistoryContainer(CalculationManager::CALCULATOR_MODE::CM_STD); - ClearHistoryContainer(CalculationManager::CALCULATOR_MODE::CM_SCI); -} - -void HistoryViewModel::SaveHistory() -{ - ApplicationDataContainer ^ historyContainer = GetHistoryContainer(m_currentMode); - auto currentHistoryVector = m_calculatorManager->GetHistoryItems(m_currentMode); - bool failure = false; - int index = 0; - Platform::String ^ serializedHistoryItem; - - for (auto iter = currentHistoryVector.begin(); iter != currentHistoryVector.end(); ++iter) - { - try - { - serializedHistoryItem = SerializeHistoryItem(*iter); - historyContainer->Values->Insert(index.ToString(), serializedHistoryItem); - } - catch (Platform::Exception ^) - { - failure = true; - break; - } - - ++index; - } - - if (!failure) - { - // insertion is successful - UpdateHistoryVectorLength(static_cast(currentHistoryVector.size()), m_currentMode); - } - else - { - UpdateHistoryVectorLength(0, m_currentMode); - } -} - -// this serializes a history item into a base64 encoded string -Platform::String ^ HistoryViewModel::SerializeHistoryItem(_In_ std::shared_ptr const& item) -{ - DataWriter ^ writer = ref new DataWriter(); - auto expr = item->historyItemVector.expression; - auto result = item->historyItemVector.result; - auto platformExpr = ref new Platform::String(expr.c_str()); - writer->WriteUInt32(writer->MeasureString(platformExpr)); - writer->WriteString(platformExpr); - auto platformResult = ref new Platform::String(result.c_str()); - writer->WriteUInt32(writer->MeasureString(platformResult)); - writer->WriteString(platformResult); - - Utils::SerializeCommandsAndTokens(item->historyItemVector.spTokens, item->historyItemVector.spCommands, writer); - - IBuffer ^ buffer = writer->DetachBuffer(); - if (buffer == nullptr) - { - throw ref new Platform::Exception(E_POINTER, ref new Platform::String(L"History Item is NULL")); - } - - return CryptographicBuffer::EncodeToBase64String(buffer); -} - -CalculationManager::HISTORYITEM -HistoryViewModel::DeserializeHistoryItem(_In_ Platform::String ^ historyItemKey, _In_ ApplicationDataContainer ^ historyContainer) -{ - CalculationManager::HISTORYITEM historyItem; - if (historyContainer->Values->HasKey(historyItemKey)) - { - Object ^ historyItemValues = historyContainer->Values->Lookup(historyItemKey); - - if (historyItemValues == nullptr) - { - throw ref new Platform::Exception(E_POINTER, ref new Platform::String(L"History Item is NULL")); - } - - String ^ historyData = safe_cast(historyItemValues); - IBuffer ^ buffer = CryptographicBuffer::DecodeFromBase64String(historyData); - - if (buffer == nullptr) - { - throw ref new Platform::Exception(E_POINTER, ref new Platform::String(L"History Item is NULL")); - } - - DataReader ^ reader = DataReader::FromBuffer(buffer); - auto exprLen = reader->ReadUInt32(); - auto expression = reader->ReadString(exprLen); - historyItem.historyItemVector.expression = expression->Data(); - - auto resultLen = reader->ReadUInt32(); - auto result = reader->ReadString(resultLen); - historyItem.historyItemVector.result = result->Data(); - - historyItem.historyItemVector.spCommands = Utils::DeserializeCommands(reader); - historyItem.historyItemVector.spTokens = Utils::DeserializeTokens(reader); - } - else - { - throw ref new Platform::Exception(E_ACCESSDENIED, ref new Platform::String(L"History Item not found")); - } - return historyItem; -} - -bool HistoryViewModel::IsValid(_In_ CalculationManager::HISTORYITEM item) -{ - return ( - !item.historyItemVector.expression.empty() && !item.historyItemVector.result.empty() && (bool)item.historyItemVector.spCommands - && (bool)item.historyItemVector.spTokens); -} - -void HistoryViewModel::UpdateItemSize() -{ - ItemSize = Items->Size; -} - -void HistoryViewModel::MakeHistoryClearedNarratorAnnouncement(String ^ resourceKey, String ^ &formatVariable) -{ - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(resourceKey, formatVariable); - - HistoryAnnouncement = CalculatorAnnouncement::GetHistoryClearedAnnouncement(announcement); -} diff --git a/src/CalcViewModel/HistoryViewModel.h b/src/CalcViewModel/HistoryViewModel.h deleted file mode 100644 index 4ed61d92..00000000 --- a/src/CalcViewModel/HistoryViewModel.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/CalculatorManager.h" -#include "Common/Automation/NarratorAnnouncement.h" -#include "Common/CalculatorDisplay.h" -#include "Common/NavCategory.h" -#include "HistoryItemViewModel.h" - -namespace CalculatorApp -{ - namespace CM = CalculationManager; - - namespace ViewModel - { - public - delegate void HideHistoryClickedHandler(); - public - delegate void HistoryItemClickedHandler(CalculatorApp::ViewModel::HistoryItemViewModel ^ e); - - [Windows::UI::Xaml::Data::Bindable] public ref class HistoryViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - public: - OBSERVABLE_OBJECT(); - OBSERVABLE_PROPERTY_RW(int, ItemSize); - OBSERVABLE_PROPERTY_RW(Windows::UI::Xaml::Interop::IBindableObservableVector ^, Items); - OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled); - OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement ^, HistoryAnnouncement); - - void OnHistoryItemAdded(_In_ unsigned int addedItemIndex); - - COMMAND_FOR_METHOD(HideCommand, HistoryViewModel::OnHideCommand); - void OnHideCommand(_In_ Platform::Object ^ e); - COMMAND_FOR_METHOD(ClearCommand, HistoryViewModel::OnClearCommand); - void OnClearCommand(_In_ Platform::Object ^ e); - - // events that are created - event HideHistoryClickedHandler ^ HideHistoryClicked; - event HistoryItemClickedHandler ^ HistoryItemClicked; - void ShowItem(_In_ CalculatorApp::ViewModel::HistoryItemViewModel ^ e); - void ClearHistory(); - void RestoreCompleteHistory(); - - internal : HistoryViewModel(_In_ CalculationManager::CalculatorManager* calculatorManager); - void SetCalculatorDisplay(CalculatorDisplay& calculatorDisplay); - void ReloadHistory(_In_ CalculatorApp::Common::ViewMode currentMode); - - void DeleteItem(_In_ CalculatorApp::ViewModel::HistoryItemViewModel ^ e); - - // store history in app data functions - Platform::String ^ SerializeHistoryItem(_In_ std::shared_ptr const& item); - void SaveHistory(); - - private: - CalculationManager::CalculatorManager* const m_calculatorManager; - CalculatorDisplay m_calculatorDisplay; - CalculationManager::CALCULATOR_MODE m_currentMode; - Platform::String ^ m_localizedHistoryCleared; - - void RestoreHistory(_In_ CalculationManager::CALCULATOR_MODE cMode); - CalculationManager::HISTORYITEM - DeserializeHistoryItem(_In_ Platform::String ^ historyItemKey, _In_ Windows::Storage::ApplicationDataContainer ^ historyContainer); - Windows::Storage::ApplicationDataContainer ^ GetHistoryContainer(_In_ CalculationManager::CALCULATOR_MODE cMode); - Platform::String ^ GetHistoryContainerKey(_In_ CalculationManager::CALCULATOR_MODE cMode); - void ClearHistoryContainer(_In_ CalculationManager::CALCULATOR_MODE cMode); - void UpdateHistoryVectorLength(_In_ int newValue, _In_ CalculationManager::CALCULATOR_MODE cMode); - bool IsValid(_In_ CalculationManager::HISTORYITEM item); - - void MakeHistoryClearedNarratorAnnouncement(Platform::String ^ resourceKey, Platform::String ^ &formatVariable); - - friend class CalculatorDisplay; - void UpdateItemSize(); - }; - } -} diff --git a/src/CalcViewModel/MemoryItemViewModel.cpp b/src/CalcViewModel/MemoryItemViewModel.cpp deleted file mode 100644 index b7d21649..00000000 --- a/src/CalcViewModel/MemoryItemViewModel.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "MemoryItemViewModel.h" -#include "StandardCalculatorViewModel.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::Automation; -using namespace CalculatorApp::ViewModel; -using namespace Platform; -using namespace std; -using namespace Windows::Foundation; -using namespace Windows::Storage; -using namespace Windows::Storage::Streams; -using namespace Windows::Security::Cryptography; -using namespace Windows::Foundation::Collections; - -void MemoryItemViewModel::Clear() -{ - m_calcVM->OnMemoryClear(Position); -}; - -void MemoryItemViewModel::MemoryAdd() -{ - m_calcVM->OnMemoryAdd(Position); -}; - -void MemoryItemViewModel::MemorySubtract() -{ - m_calcVM->OnMemorySubtract(Position); -}; diff --git a/src/CalcViewModel/MemoryItemViewModel.h b/src/CalcViewModel/MemoryItemViewModel.h deleted file mode 100644 index 9a85a2bc..00000000 --- a/src/CalcViewModel/MemoryItemViewModel.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "Common/Utils.h" - -namespace CalculatorApp -{ - namespace ViewModel - { - ref class StandardCalculatorViewModel; - - /// - /// Model representation of a single item in the Memory list - /// - [Windows::UI::Xaml::Data::Bindable] public ref class MemoryItemViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged, - Windows::UI::Xaml::Data::ICustomPropertyProvider - { - public: - MemoryItemViewModel(StandardCalculatorViewModel ^ calcVM) - : m_Position(-1) - , m_calcVM(calcVM) - { - } - OBSERVABLE_OBJECT(); - OBSERVABLE_PROPERTY_RW(int, Position); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Value); - - virtual Windows::UI::Xaml::Data::ICustomProperty - ^ GetCustomProperty(Platform::String ^ name) { return nullptr; } - - virtual Windows::UI::Xaml::Data::ICustomProperty - ^ GetIndexedProperty(Platform::String ^ name, Windows::UI::Xaml::Interop::TypeName type) { return nullptr; } - - virtual property Windows::UI::Xaml::Interop::TypeName Type - { - Windows::UI::Xaml::Interop::TypeName get() - { - return this->GetType(); - } - } - - virtual Platform::String - ^ GetStringRepresentation() { return Value; } - - void Clear(); - void MemoryAdd(); - void MemorySubtract(); - - private: - StandardCalculatorViewModel ^ m_calcVM; - }; - } -} diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp deleted file mode 100644 index 6acda106..00000000 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ /dev/null @@ -1,1974 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "StandardCalculatorViewModel.h" -#include "Common/CalculatorButtonPressedEventArgs.h" -#include "Common/LocalizationStringUtil.h" -#include "Common/LocalizationSettings.h" -#include "Common/CopyPasteManager.h" -#include "Common/TraceLogger.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::Automation; -using namespace CalculatorApp::ViewModel; -using namespace CalculationManager; -using namespace Platform; -using namespace Platform::Collections; -using namespace std; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::Foundation; -using namespace Windows::System; -using namespace Windows::UI::Core; -using namespace Windows::UI::Popups; -using namespace Windows::Storage::Streams; -using namespace Windows::Foundation::Collections; -using namespace Utils; - -constexpr int StandardModePrecision = 16; -constexpr int ScientificModePrecision = 32; -constexpr int ProgrammerModePrecision = 64; - -namespace -{ - StringReference IsStandardPropertyName(L"IsStandard"); - StringReference IsScientificPropertyName(L"IsScientific"); - StringReference IsProgrammerPropertyName(L"IsProgrammer"); - StringReference DisplayValuePropertyName(L"DisplayValue"); - StringReference CalculationResultAutomationNamePropertyName(L"CalculationResultAutomationName"); -} - -namespace CalculatorResourceKeys -{ - StringReference CalculatorExpression(L"Format_CalculatorExpression"); - StringReference CalculatorResults(L"Format_CalculatorResults"); - StringReference CalculatorResults_DecimalSeparator_Announced(L"Format_CalculatorResults_Decimal"); - StringReference HexButton(L"Format_HexButtonValue"); - StringReference DecButton(L"Format_DecButtonValue"); - StringReference OctButton(L"Format_OctButtonValue"); - StringReference BinButton(L"Format_BinButtonValue"); - StringReference OpenParenthesisCountAutomationFormat(L"Format_OpenParenthesisCountAutomationNamePrefix"); - StringReference NoParenthesisAdded(L"NoRightParenthesisAdded_Announcement"); - StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached"); - StringReference ButtonPressFeedbackFormat(L"Format_ButtonPressAuditoryFeedback"); - StringReference MemorySave(L"Format_MemorySave"); - StringReference MemoryItemChanged(L"Format_MemorySlotChanged"); - StringReference MemoryItemCleared(L"Format_MemorySlotCleared"); - StringReference MemoryCleared(L"Memory_Cleared"); - StringReference DisplayCopied(L"Display_Copied"); -} - -StandardCalculatorViewModel::StandardCalculatorViewModel() - : m_DisplayValue(L"0") - , m_DecimalDisplayValue(L"0") - , m_HexDisplayValue(L"0") - , m_BinaryDisplayValue(L"0") - , m_OctalDisplayValue(L"0") - , m_standardCalculatorManager(&m_calculatorDisplay, &m_resourceProvider) - , m_ExpressionTokens(ref new Vector()) - , m_MemorizedNumbers(ref new Vector()) - , m_IsMemoryEmpty(true) - , m_IsFToEChecked(false) - , m_isShiftChecked(false) - , m_IsShiftProgrammerChecked(false) - , m_IsQwordEnabled(true) - , m_IsDwordEnabled(true) - , m_IsWordEnabled(true) - , m_IsByteEnabled(true) - , m_isBitFlipChecked(false) - , m_isBinaryBitFlippingEnabled(false) - , m_CurrentRadixType(RADIX_TYPE::DEC_RADIX) - , m_CurrentAngleType(NumbersAndOperatorsEnum::Degree) - , m_Announcement(nullptr) - , m_OpenParenthesisCount(0) - , m_feedbackForButtonPress(nullptr) - , m_isRtlLanguage(false) - , m_localizedMaxDigitsReachedAutomationFormat(nullptr) - , m_localizedButtonPressFeedbackAutomationFormat(nullptr) - , m_localizedMemorySavedAutomationFormat(nullptr) - , m_localizedMemoryItemChangedAutomationFormat(nullptr) - , m_localizedMemoryItemClearedAutomationFormat(nullptr) - , m_localizedMemoryCleared(nullptr) - , m_localizedOpenParenthesisCountChangedAutomationFormat(nullptr) - , m_localizedNoRightParenthesisAddedFormat(nullptr) -{ - WeakReference calculatorViewModel(this); - m_calculatorDisplay.SetCallback(calculatorViewModel); - m_expressionAutomationNameFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::CalculatorExpression); - m_localizedCalculationResultAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::CalculatorResults); - m_localizedCalculationResultDecimalAutomationFormat = - AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::CalculatorResults_DecimalSeparator_Announced); - m_localizedHexaDecimalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::HexButton); - m_localizedDecimalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::DecButton); - m_localizedOctalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::OctButton); - m_localizedBinaryAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::BinButton); - - // Initialize the Automation Name - CalculationResultAutomationName = GetLocalizedStringFormat(m_localizedCalculationResultAutomationFormat, m_DisplayValue); - CalculationExpressionAutomationName = GetLocalizedStringFormat(m_expressionAutomationNameFormat, L""); - - // Initialize history view model - m_HistoryVM = ref new HistoryViewModel(&m_standardCalculatorManager); - m_HistoryVM->SetCalculatorDisplay(m_calculatorDisplay); - - m_decimalSeparator = LocalizationSettings::GetInstance().GetDecimalSeparator(); - - if (CoreWindow::GetForCurrentThread() != nullptr) - { - // Must have a CoreWindow to access the resource context. - m_isRtlLanguage = LocalizationService::GetInstance()->IsRtlLayout(); - } - - IsEditingEnabled = false; - IsUnaryOperatorEnabled = true; - IsBinaryOperatorEnabled = true; - IsOperandEnabled = true; - IsNegateEnabled = true; - IsDecimalEnabled = true; - AreHistoryShortcutsEnabled = true; - AreProgrammerRadixOperatorsEnabled = false; - - m_tokenPosition = -1; - m_isLastOperationHistoryLoad = false; -} - -String ^ StandardCalculatorViewModel::LocalizeDisplayValue(_In_ wstring const& displayValue, _In_ bool isError) -{ - wstring result(displayValue); - - LocalizationSettings::GetInstance().LocalizeDisplayValue(&result); - - // WINBLUE: 440747 - In BiDi languages, error messages need to be wrapped in LRE/PDF - if (isError && m_isRtlLanguage) - { - result.insert(result.begin(), Utils::LRE); - result.push_back(Utils::PDF); - } - - return ref new Platform::String(result.c_str()); -} - -String ^ StandardCalculatorViewModel::CalculateNarratorDisplayValue(_In_ wstring const& displayValue, _In_ String ^ localizedDisplayValue, _In_ bool isError) -{ - String ^ localizedValue = localizedDisplayValue; - String ^ automationFormat = m_localizedCalculationResultAutomationFormat; - - // The narrator doesn't read the decimalSeparator if it's the last character - if (Utils::IsLastCharacterTarget(displayValue, m_decimalSeparator)) - { - // remove the decimal separator, to avoid a long pause between words - localizedValue = LocalizeDisplayValue(displayValue.substr(0, displayValue.length() - 1), isError); - - // Use a format which has a word in the decimal separator's place - // "The Display is 10 point" - automationFormat = m_localizedCalculationResultDecimalAutomationFormat; - } - - // In Programmer modes using non-base10, we want the strings to be read as literal digits. - if (IsProgrammer && CurrentRadixType != RADIX_TYPE::DEC_RADIX) - { - localizedValue = GetNarratorStringReadRawNumbers(localizedValue); - } - - return GetLocalizedStringFormat(automationFormat, localizedValue); -} - -String ^ StandardCalculatorViewModel::GetNarratorStringReadRawNumbers(_In_ String ^ localizedDisplayValue) -{ - wstringstream wss; - auto& locSettings = LocalizationSettings::GetInstance(); - - // Insert a space after each digit in the string, to force Narrator to read them as separate numbers. - wstring wstrValue(localizedDisplayValue->Data()); - for (wchar_t& c : wstrValue) - { - wss << c; - if (locSettings.IsLocalizedHexDigit(c)) - { - wss << L' '; - } - } - - return ref new String(wss.str().c_str()); -} - -void StandardCalculatorViewModel::SetPrimaryDisplay(_In_ wstring const& displayStringValue, _In_ bool isError) -{ - String ^ localizedDisplayStringValue = LocalizeDisplayValue(displayStringValue, isError); - - // Set this variable before the DisplayValue is modified, Otherwise the DisplayValue will - // not match what the narrator is saying - m_CalculationResultAutomationName = CalculateNarratorDisplayValue(displayStringValue, localizedDisplayStringValue, isError); - - DisplayValue = localizedDisplayStringValue; - - IsInError = isError; - - if (IsProgrammer) - { - UpdateProgrammerPanelDisplay(); - } -} - -void StandardCalculatorViewModel::DisplayPasteError() -{ - m_standardCalculatorManager.DisplayPasteError(); -} - -void StandardCalculatorViewModel::SetParenthesisCount(_In_ unsigned int parenthesisCount) -{ - if (m_OpenParenthesisCount == parenthesisCount) - { - return; - } - - OpenParenthesisCount = parenthesisCount; - if (IsProgrammer || IsScientific) - { - SetOpenParenthesisCountNarratorAnnouncement(); - } -} - -void StandardCalculatorViewModel::SetOpenParenthesisCountNarratorAnnouncement() -{ - wstring localizedParenthesisCount = to_wstring(m_OpenParenthesisCount).c_str(); - LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount); - - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::OpenParenthesisCountAutomationFormat, - m_localizedOpenParenthesisCountChangedAutomationFormat, - localizedParenthesisCount.c_str()); - - Announcement = CalculatorAnnouncement::GetOpenParenthesisCountChangedAnnouncement(announcement); -} - -void StandardCalculatorViewModel::OnNoRightParenAdded() -{ - SetNoParenAddedNarratorAnnouncement(); -} - -void StandardCalculatorViewModel::SetNoParenAddedNarratorAnnouncement() -{ - String ^ announcement = - LocalizationStringUtil::GetLocalizedNarratorAnnouncement(CalculatorResourceKeys::NoParenthesisAdded, m_localizedNoRightParenthesisAddedFormat); - - Announcement = CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(announcement); -} - -void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionCommandType) -{ - if (selectedExpressionCommandType == CommandType::OperandCommand) - { - IsBinaryOperatorEnabled = false; - IsUnaryOperatorEnabled = false; - IsOperandEnabled = true; - IsNegateEnabled = true; - IsDecimalEnabled = true; - } - if (selectedExpressionCommandType == CommandType::BinaryCommand) - { - IsBinaryOperatorEnabled = true; - IsUnaryOperatorEnabled = false; - IsOperandEnabled = false; - IsNegateEnabled = false; - IsDecimalEnabled = false; - } - if (selectedExpressionCommandType == CommandType::UnaryCommand) - { - IsBinaryOperatorEnabled = false; - IsUnaryOperatorEnabled = true; - IsOperandEnabled = false; - IsNegateEnabled = true; - IsDecimalEnabled = false; - } -} - -void StandardCalculatorViewModel::SetExpressionDisplay( - _Inout_ shared_ptr>> const& tokens, - _Inout_ shared_ptr>> const& commands) -{ - m_tokens = tokens; - m_commands = commands; - if (!IsEditingEnabled) - { - SetTokens(tokens); - } - - CalculationExpressionAutomationName = GetCalculatorExpressionAutomationName(); - - AreTokensUpdated = true; -} - -void StandardCalculatorViewModel::SetHistoryExpressionDisplay( - _Inout_ shared_ptr>> const& tokens, - _Inout_ shared_ptr>> const& commands) -{ - m_tokens = make_shared>>(*tokens); - m_commands = make_shared>>(*commands); - IsEditingEnabled = false; - - // Setting the History Item Load Mode so that UI does not get updated with recalculation of every token - m_standardCalculatorManager.SetInHistoryItemLoadMode(true); - Recalculate(true); - m_standardCalculatorManager.SetInHistoryItemLoadMode(false); - m_isLastOperationHistoryLoad = true; -} - -void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr>> const& tokens) -{ - AreTokensUpdated = false; - - unsigned int nTokens = 0; - tokens->GetSize(&nTokens); - - if (nTokens == 0) - { - m_ExpressionTokens->Clear(); - return; - } - - pair currentToken; - const auto& localizer = LocalizationSettings::GetInstance(); - - const wstring separator = L" "; - for (unsigned int i = 0; i < nTokens; ++i) - { - if (SUCCEEDED(tokens->GetAt(i, ¤tToken))) - { - Common::TokenType type; - bool isEditable = (currentToken.second == -1) ? false : true; - localizer.LocalizeDisplayValue(&(currentToken.first)); - - if (!isEditable) - { - type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator; - } - else - { - shared_ptr command; - IFTPlatformException(m_commands->GetAt(static_cast(currentToken.second), &command)); - type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator; - } - - auto currentTokenString = ref new String(currentToken.first.c_str()); - if (i < m_ExpressionTokens->Size) - { - auto existingItem = m_ExpressionTokens->GetAt(i); - if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString)) - { - existingItem->TokenPosition = i; - existingItem->IsTokenEditable = isEditable; - existingItem->CommandIndex = 0; - } - else - { - auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); - m_ExpressionTokens->InsertAt(i, expressionToken); - } - } - else - { - auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); - m_ExpressionTokens->Append(expressionToken); - } - } - } - - while (m_ExpressionTokens->Size != nTokens) - { - m_ExpressionTokens->RemoveAtEnd(); - } -} - -String ^ StandardCalculatorViewModel::GetCalculatorExpressionAutomationName() -{ - String ^ expression = L""; - for (auto&& token : m_ExpressionTokens) - { - expression += LocalizationService::GetNarratorReadableToken(token->Token); - } - - return GetLocalizedStringFormat(m_expressionAutomationNameFormat, expression); -} - -void StandardCalculatorViewModel::SetMemorizedNumbers(const vector& newMemorizedNumbers) -{ - const auto& localizer = LocalizationSettings::GetInstance(); - if (newMemorizedNumbers.size() == 0) // Memory has been cleared - { - MemorizedNumbers->Clear(); - IsMemoryEmpty = true; - } - // A new value is added to the memory - else if (newMemorizedNumbers.size() > MemorizedNumbers->Size) - { - while (newMemorizedNumbers.size() > MemorizedNumbers->Size) - { - size_t newValuePosition = newMemorizedNumbers.size() - MemorizedNumbers->Size - 1; - auto stringValue = newMemorizedNumbers.at(newValuePosition); - - MemoryItemViewModel ^ memorySlot = ref new MemoryItemViewModel(this); - memorySlot->Position = 0; - localizer.LocalizeDisplayValue(&stringValue); - memorySlot->Value = Utils::LRO + ref new String(stringValue.c_str()) + Utils::PDF; - - MemorizedNumbers->InsertAt(0, memorySlot); - IsMemoryEmpty = false; - - // Update the slot position for the rest of the slots - for (unsigned int i = 1; i < MemorizedNumbers->Size; i++) - { - MemorizedNumbers->GetAt(i)->Position++; - } - } - } - else if (newMemorizedNumbers.size() == MemorizedNumbers->Size) // Either M+ or M- - { - for (unsigned int i = 0; i < MemorizedNumbers->Size; i++) - { - auto newStringValue = newMemorizedNumbers.at(i); - localizer.LocalizeDisplayValue(&newStringValue); - - // If the value is different, update the value - if (MemorizedNumbers->GetAt(i)->Value != StringReference(newStringValue.c_str())) - { - MemorizedNumbers->GetAt(i)->Value = Utils::LRO + ref new String(newStringValue.c_str()) + Utils::PDF; - } - } - } -} - -void StandardCalculatorViewModel::FtoEButtonToggled() -{ - OnButtonPressed(NumbersAndOperatorsEnum::FToE); -} - -void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) -{ - DisplayExpressionToken ^ displayExpressionToken = ExpressionTokens->GetAt(m_tokenPosition); - if (displayExpressionToken == nullptr) - { - return; - } - if ((displayExpressionToken->Token == nullptr) || (displayExpressionToken->Token->Length() == 0)) - { - displayExpressionToken->CommandIndex = 0; - } - - wchar_t ch = 0; - if ((cmdenum >= Command::Command0) && (cmdenum <= Command::Command9)) - { - switch (cmdenum) - { - case Command::Command0: - ch = L'0'; - break; - case Command::Command1: - ch = L'1'; - break; - case Command::Command2: - ch = L'2'; - break; - case Command::Command3: - ch = L'3'; - break; - case Command::Command4: - ch = L'4'; - break; - case Command::Command5: - ch = L'5'; - break; - case Command::Command6: - ch = L'6'; - break; - case Command::Command7: - ch = L'7'; - break; - case Command::Command8: - ch = L'8'; - break; - case Command::Command9: - ch = L'9'; - break; - } - } - else if (cmdenum == Command::CommandPNT) - { - ch = L'.'; - } - else if (cmdenum == Command::CommandBACK) - { - ch = L'x'; - } - else - { - return; - } - - int length = 0; - wchar_t* temp = new wchar_t[100]; - const wchar_t* data = m_selectedExpressionLastData->Data(); - int i = 0, j = 0; - int commandIndex = displayExpressionToken->CommandIndex; - - if (IsOperandTextCompletelySelected) - { - // Clear older text; - m_selectedExpressionLastData = L""; - if (ch == L'x') - { - temp[0] = L'\0'; - commandIndex = 0; - } - else - { - temp[0] = ch; - temp[1] = L'\0'; - commandIndex = 1; - } - IsOperandTextCompletelySelected = false; - } - else - { - if (ch == L'x') - { - if (commandIndex == 0) - { - delete[] temp; - return; - } - - length = m_selectedExpressionLastData->Length(); - for (; j < length; ++j) - { - if (j == commandIndex - 1) - { - continue; - } - temp[i++] = data[j]; - } - temp[i] = L'\0'; - commandIndex -= 1; - } - else - { - length = m_selectedExpressionLastData->Length() + 1; - if (length > 50) - { - delete[] temp; - return; - } - for (; i < length; ++i) - { - if (i == commandIndex) - { - temp[i] = ch; - continue; - } - temp[i] = data[j++]; - } - temp[i] = L'\0'; - commandIndex += 1; - } - } - - String ^ updatedData = ref new String(temp); - UpdateOperand(m_tokenPosition, updatedData); - displayExpressionToken->Token = updatedData; - IsOperandUpdatedUsingViewModel = true; - displayExpressionToken->CommandIndex = commandIndex; -} - -bool StandardCalculatorViewModel::IsOperator(Command cmdenum) -{ - if ((cmdenum >= Command::Command0 && cmdenum <= Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) - || (cmdenum == Command::CommandEXP) || (cmdenum == Command::CommandFE) || (cmdenum == Command::ModeBasic) || (cmdenum == Command::ModeProgrammer) - || (cmdenum == Command::ModeScientific) || (cmdenum == Command::CommandINV) || (cmdenum == Command::CommandCENTR) || (cmdenum == Command::CommandDEG) - || (cmdenum == Command::CommandRAD) || (cmdenum == Command::CommandGRAD) - || ((cmdenum >= Command::CommandBINEDITSTART) && (cmdenum <= Command::CommandBINEDITEND))) - { - return false; - } - return true; -} - -void StandardCalculatorViewModel::OnButtonPressed(Object ^ parameter) -{ - m_feedbackForButtonPress = CalculatorButtonPressedEventArgs::GetAuditoryFeedbackFromCommandParameter(parameter); - NumbersAndOperatorsEnum numOpEnum = CalculatorButtonPressedEventArgs::GetOperationFromCommandParameter(parameter); - Command cmdenum = ConvertToOperatorsEnum(numOpEnum); - - TraceLogger::GetInstance().UpdateFunctionUsage((int)numOpEnum); - - if (IsInError) - { - m_standardCalculatorManager.SendCommand(Command::CommandCLEAR); - - if (!IsRecoverableCommand((int)numOpEnum)) - { - return; - } - } - - if (IsEditingEnabled && numOpEnum != NumbersAndOperatorsEnum::IsScientificMode && numOpEnum != NumbersAndOperatorsEnum::IsStandardMode - && numOpEnum != NumbersAndOperatorsEnum::IsProgrammerMode && numOpEnum != NumbersAndOperatorsEnum::FToE - && (numOpEnum != NumbersAndOperatorsEnum::Degree) && (numOpEnum != NumbersAndOperatorsEnum::Radians) && (numOpEnum != NumbersAndOperatorsEnum::Grads)) - { - if (!m_keyPressed) - { - SaveEditedCommand(m_selectedExpressionToken->TokenPosition, cmdenum); - } - } - else - { - if (numOpEnum == NumbersAndOperatorsEnum::IsStandardMode || numOpEnum == NumbersAndOperatorsEnum::IsScientificMode - || numOpEnum == NumbersAndOperatorsEnum::IsProgrammerMode) - { - IsEditingEnabled = false; - } - if (numOpEnum == NumbersAndOperatorsEnum::Memory) - { - OnMemoryButtonPressed(); - } - else - { - if (numOpEnum == NumbersAndOperatorsEnum::Clear || numOpEnum == NumbersAndOperatorsEnum::ClearEntry - || numOpEnum == NumbersAndOperatorsEnum::IsStandardMode || numOpEnum == NumbersAndOperatorsEnum::IsProgrammerMode) - { - // On Clear('C') the F-E button needs to be UnChecked if it in Checked state. - // Also, the Primary Display Value should not show in exponential format. - // Hence the check below to ensure parity with Desktop Calculator. - // Clear the FE mode if the switching to StandardMode, since 'C'/'CE' in StandardMode - // doesn't honor the FE button. - if (IsFToEChecked) - { - IsFToEChecked = false; - } - } - if (numOpEnum == NumbersAndOperatorsEnum::Degree || numOpEnum == NumbersAndOperatorsEnum::Radians || numOpEnum == NumbersAndOperatorsEnum::Grads) - { - m_CurrentAngleType = numOpEnum; - } - if ((cmdenum >= Command::Command0 && cmdenum <= Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) - || (cmdenum == Command::CommandEXP)) - { - IsOperatorCommand = false; - } - else - { - IsOperatorCommand = true; - } - - if (m_isLastOperationHistoryLoad - && ((numOpEnum != NumbersAndOperatorsEnum::Degree) && (numOpEnum != NumbersAndOperatorsEnum::Radians) - && (numOpEnum != NumbersAndOperatorsEnum::Grads))) - { - IsFToEEnabled = true; - m_isLastOperationHistoryLoad = false; - } - - m_standardCalculatorManager.SendCommand(cmdenum); - } - } -} - -int StandardCalculatorViewModel::GetBitLengthType() -{ - if (IsQwordEnabled) - { - return QwordType; - } - else if (IsDwordEnabled) - { - return DwordType; - } - else if (IsWordEnabled) - { - return WordType; - } - else - { - return ByteType; - } -} - -int StandardCalculatorViewModel::GetNumberBase() -{ - if (CurrentRadixType == HEX_RADIX) - { - return HexBase; - } - else if (CurrentRadixType == DEC_RADIX) - { - return DecBase; - } - else if (CurrentRadixType == OCT_RADIX) - { - return OctBase; - } - else - { - return BinBase; - } -} - -void StandardCalculatorViewModel::OnCopyCommand(Object ^ parameter) -{ - CopyPasteManager::CopyToClipboard(GetRawDisplayValue()); - - String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::DisplayCopied); - Announcement = CalculatorAnnouncement::GetDisplayCopiedAnnouncement(announcement); -} - -void StandardCalculatorViewModel::OnPasteCommand(Object ^ parameter) -{ - ViewMode mode; - int NumberBase = -1; - int bitLengthType = -1; - if (IsScientific) - { - mode = ViewMode::Scientific; - } - else if (IsProgrammer) - { - mode = ViewMode::Programmer; - NumberBase = GetNumberBase(); - bitLengthType = GetBitLengthType(); - } - else - { - mode = ViewMode::Standard; - } - // if there's nothing to copy early out - if (IsEditingEnabled || !CopyPasteManager::HasStringToPaste()) - { - return; - } - - // Ensure that the paste happens on the UI thread - CopyPasteManager::GetStringToPaste(mode, NavCategory::GetGroupType(mode), NumberBase, bitLengthType) - .then([this, mode](String ^ pastedString) { OnPaste(pastedString, mode); }, concurrency::task_continuation_context::use_current()); -} - -CalculationManager::Command StandardCalculatorViewModel::ConvertToOperatorsEnum(NumbersAndOperatorsEnum operation) -{ - return safe_cast(operation); -} - -void StandardCalculatorViewModel::OnPaste(String ^ pastedString, ViewMode mode) -{ - // If pastedString is invalid("NoOp") then display pasteError else process the string - if (pastedString == StringReference(CopyPasteManager::PasteErrorString)) - { - this->DisplayPasteError(); - return; - } - - TraceLogger::GetInstance().LogValidInputPasted(mode); - bool isFirstLegalChar = true; - m_standardCalculatorManager.SendCommand(Command::CommandCENTR); - bool sendNegate = false; - bool processedDigit = false; - bool sentEquals = false; - bool isPreviousOperator = false; - - vector negateStack; - - // Iterate through each character pasted, and if it's valid, send it to the model. - auto it = pastedString->Begin(); - - while (it != pastedString->End()) - { - bool sendCommand = true; - bool canSendNegate = false; - - NumbersAndOperatorsEnum mappedNumOp = MapCharacterToButtonId(*it, canSendNegate); - - if (mappedNumOp == NumbersAndOperatorsEnum::None) - { - ++it; - continue; - } - - if (isFirstLegalChar || isPreviousOperator) - { - isFirstLegalChar = false; - isPreviousOperator = false; - - // If the character is a - sign, send negate - // after sending the next legal character. Send nothing now, or - // it will be ignored. - if (NumbersAndOperatorsEnum::Subtract == mappedNumOp) - { - sendNegate = true; - sendCommand = false; - } - - // Support (+) sign prefix - if (NumbersAndOperatorsEnum::Add == mappedNumOp) - { - sendCommand = false; - } - } - - switch (mappedNumOp) - { - // Opening parenthesis starts a new expression and pushes negation state onto the stack - case NumbersAndOperatorsEnum::OpenParenthesis: - negateStack.push_back(sendNegate); - sendNegate = false; - break; - - // Closing parenthesis pops the negation state off the stack and sends it down to the calc engine - case NumbersAndOperatorsEnum::CloseParenthesis: - if (!negateStack.empty()) - { - sendNegate = negateStack.back(); - negateStack.pop_back(); - canSendNegate = true; - } - else - { - // Don't send a closing parenthesis if a matching opening parenthesis hasn't been sent already - sendCommand = false; - } - break; - - case NumbersAndOperatorsEnum::Zero: - case NumbersAndOperatorsEnum::One: - case NumbersAndOperatorsEnum::Two: - case NumbersAndOperatorsEnum::Three: - case NumbersAndOperatorsEnum::Four: - case NumbersAndOperatorsEnum::Five: - case NumbersAndOperatorsEnum::Six: - case NumbersAndOperatorsEnum::Seven: - case NumbersAndOperatorsEnum::Eight: - case NumbersAndOperatorsEnum::Nine: - processedDigit = true; - break; - - case NumbersAndOperatorsEnum::Add: - case NumbersAndOperatorsEnum::Subtract: - case NumbersAndOperatorsEnum::Multiply: - case NumbersAndOperatorsEnum::Divide: - isPreviousOperator = true; - break; - } - - if (sendCommand) - { - sentEquals = (mappedNumOp == NumbersAndOperatorsEnum::Equals); - Command cmdenum = ConvertToOperatorsEnum(mappedNumOp); - m_standardCalculatorManager.SendCommand(cmdenum); - - // The CalcEngine state machine won't allow the negate command to be sent before any - // other digits, so instead a flag is set and the command is sent after the first appropriate - // command. - if (sendNegate) - { - if (canSendNegate) - { - Command cmdNegate = ConvertToOperatorsEnum(NumbersAndOperatorsEnum::Negate); - m_standardCalculatorManager.SendCommand(cmdNegate); - } - - // Can't send negate on a leading zero, so wait until the appropriate time to send it. - if (NumbersAndOperatorsEnum::Zero != mappedNumOp && NumbersAndOperatorsEnum::Decimal != mappedNumOp) - { - sendNegate = false; - } - } - } - - // Handle exponent and exponent sign (...e+... or ...e-...) - if (mappedNumOp == NumbersAndOperatorsEnum::Exp) - { - ++it; - if (!(MapCharacterToButtonId(*it, canSendNegate) == NumbersAndOperatorsEnum::Add)) - { - Command cmdNegate = ConvertToOperatorsEnum(NumbersAndOperatorsEnum::Negate); - m_standardCalculatorManager.SendCommand(cmdNegate); - } - } - - ++it; - } -} - -void StandardCalculatorViewModel::OnClearMemoryCommand(Object ^ parameter) -{ - m_standardCalculatorManager.MemorizedNumberClearAll(); - - int windowId = Utils::GetWindowId(); - TraceLogger::GetInstance().LogMemoryClearAll(windowId); - - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(CalculatorResourceKeys::MemoryCleared, m_localizedMemoryCleared); - Announcement = CalculatorAnnouncement::GetMemoryClearedAnnouncement(announcement); -} - -void StandardCalculatorViewModel::OnPinUnpinCommand(Object ^ parameter) -{ - SetViewPinnedState(!IsViewPinned()); -} - -bool StandardCalculatorViewModel::IsViewPinned() -{ - return m_IsCurrentViewPinned; -} - -void StandardCalculatorViewModel::SetViewPinnedState(bool pinned) -{ - IsCurrentViewPinned = pinned; -} - -NumbersAndOperatorsEnum StandardCalculatorViewModel::MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate) -{ - NumbersAndOperatorsEnum mappedValue = NumbersAndOperatorsEnum::None; - canSendNegate = false; - - switch (ch) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - mappedValue = NumbersAndOperatorsEnum::Zero + static_cast(ch - L'0'); - canSendNegate = true; - break; - - case '*': - mappedValue = NumbersAndOperatorsEnum::Multiply; - break; - - case '+': - mappedValue = NumbersAndOperatorsEnum::Add; - break; - - case '-': - mappedValue = NumbersAndOperatorsEnum::Subtract; - break; - - case '/': - mappedValue = NumbersAndOperatorsEnum::Divide; - break; - - case '=': - mappedValue = NumbersAndOperatorsEnum::Equals; - break; - - case '(': - mappedValue = NumbersAndOperatorsEnum::OpenParenthesis; - break; - - case ')': - mappedValue = NumbersAndOperatorsEnum::CloseParenthesis; - break; - - case 'a': - case 'A': - mappedValue = NumbersAndOperatorsEnum::A; - break; - case 'b': - case 'B': - mappedValue = NumbersAndOperatorsEnum::B; - break; - case 'c': - case 'C': - mappedValue = NumbersAndOperatorsEnum::C; - break; - case 'd': - case 'D': - mappedValue = NumbersAndOperatorsEnum::D; - break; - case 'e': - case 'E': - // Only allow scientific notation in scientific mode - if (IsProgrammer) - { - mappedValue = NumbersAndOperatorsEnum::E; - } - else - { - mappedValue = NumbersAndOperatorsEnum::Exp; - } - break; - case 'f': - case 'F': - mappedValue = NumbersAndOperatorsEnum::F; - break; - default: - // For the decimalSeparator, we need to respect the user setting. - if (ch == m_decimalSeparator) - { - mappedValue = NumbersAndOperatorsEnum::Decimal; - } - break; - } - - if (mappedValue == NumbersAndOperatorsEnum::None) - { - if (LocalizationSettings::GetInstance().IsLocalizedDigit(ch)) - { - mappedValue = - NumbersAndOperatorsEnum::Zero + static_cast(ch - LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit('0')); - canSendNegate = true; - } - } - - // Negate cannot be sent for leading zeroes - if (NumbersAndOperatorsEnum::Zero == mappedValue) - { - canSendNegate = false; - } - - return mappedValue; -} - -void StandardCalculatorViewModel::OnMemoryButtonPressed() -{ - m_standardCalculatorManager.MemorizeNumber(); - - int windowId = Utils::GetWindowId(); - TraceLogger::GetInstance().InsertIntoMemoryMap(windowId, IsStandard, IsScientific, IsProgrammer); - - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MemorySave, m_localizedMemorySavedAutomationFormat, m_DisplayValue->Data()); - - Announcement = CalculatorAnnouncement::GetMemoryItemAddedAnnouncement(announcement); -} - -void StandardCalculatorViewModel::OnMemoryItemChanged(unsigned int indexOfMemory) -{ - if (indexOfMemory < MemorizedNumbers->Size) - { - MemoryItemViewModel ^ memSlot = MemorizedNumbers->GetAt(indexOfMemory); - String ^ localizedValue = memSlot->Value; - - wstring localizedIndex = to_wstring(indexOfMemory + 1); - LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedIndex); - - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MemoryItemChanged, m_localizedMemoryItemChangedAutomationFormat, localizedIndex.c_str(), localizedValue->Data()); - - Announcement = CalculatorAnnouncement::GetMemoryItemChangedAnnouncement(announcement); - } -} - -void StandardCalculatorViewModel::OnMemoryItemPressed(Object ^ memoryItemPosition) -{ - if (MemorizedNumbers && MemorizedNumbers->Size > 0) - { - auto boxedPosition = safe_cast ^>(memoryItemPosition); - m_standardCalculatorManager.MemorizedNumberLoad(boxedPosition->Value); - HideMemoryClicked(); - int windowId = Utils::GetWindowId(); - TraceLogger::GetInstance().LogMemoryUsed(windowId, boxedPosition->Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers->Size); - } -} - -void StandardCalculatorViewModel::OnMemoryAdd(Object ^ memoryItemPosition) -{ - // M+ will add display to memorylist if memory list is empty. - int windowId = Utils::GetWindowId(); - - if (MemorizedNumbers) - { - auto boxedPosition = safe_cast ^>(memoryItemPosition); - if (MemorizedNumbers->Size > 0) - { - TraceLogger::GetInstance().LogMemoryUsed(windowId, boxedPosition->Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers->Size); - TraceLogger::GetInstance().UpdateMemoryMap(windowId, boxedPosition->Value, IsStandard, IsScientific, IsProgrammer); - } - else - { - TraceLogger::GetInstance().InsertIntoMemoryMap(windowId, IsStandard, IsScientific, IsProgrammer); - } - m_standardCalculatorManager.MemorizedNumberAdd(boxedPosition->Value); - } -} - -void StandardCalculatorViewModel::OnMemorySubtract(Object ^ memoryItemPosition) -{ - int windowId = Utils::GetWindowId(); - - // M- will add negative of displayed number to memorylist if memory list is empty. - if (MemorizedNumbers) - { - auto boxedPosition = safe_cast ^>(memoryItemPosition); - if (MemorizedNumbers->Size > 0) - { - TraceLogger::GetInstance().LogMemoryUsed(windowId, boxedPosition->Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers->Size); - TraceLogger::GetInstance().UpdateMemoryMap(windowId, boxedPosition->Value, IsStandard, IsScientific, IsProgrammer); - } - else - { - TraceLogger::GetInstance().InsertIntoMemoryMap(windowId, IsStandard, IsScientific, IsProgrammer); - } - m_standardCalculatorManager.MemorizedNumberSubtract(boxedPosition->Value); - } -} - -void StandardCalculatorViewModel::OnMemoryClear(_In_ Object ^ memoryItemPosition) -{ - if (MemorizedNumbers && MemorizedNumbers->Size > 0) - { - int windowId = Utils::GetWindowId(); - auto boxedPosition = safe_cast ^>(memoryItemPosition); - - if (boxedPosition->Value >= 0) - { - unsigned int unsignedPosition = safe_cast(boxedPosition->Value); - m_standardCalculatorManager.MemorizedNumberClear(unsignedPosition); - - MemorizedNumbers->RemoveAt(unsignedPosition); - for (unsigned int i = 0; i < MemorizedNumbers->Size; i++) - { - MemorizedNumbers->GetAt(i)->Position = i; - } - - if (MemorizedNumbers->Size == 0) - { - IsMemoryEmpty = true; - } - - TraceLogger::GetInstance().LogMemoryUsed(windowId, boxedPosition->Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers->Size); - TraceLogger::GetInstance().DeleteFromMemoryMap(windowId, boxedPosition->Value); - - wstring localizedIndex = to_wstring(boxedPosition->Value + 1); - LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedIndex); - - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MemoryItemCleared, m_localizedMemoryItemClearedAutomationFormat, localizedIndex.c_str()); - - Announcement = CalculatorAnnouncement::GetMemoryClearedAnnouncement(announcement); - } - } -} - -Array ^ StandardCalculatorViewModel::Serialize() -{ - DataWriter ^ writer = ref new DataWriter(); - writer->WriteUInt32(static_cast(m_CurrentAngleType)); - writer->WriteBoolean(IsFToEChecked); - writer->WriteBoolean(IsCurrentViewPinned); - writer->WriteUInt32(static_cast(m_standardCalculatorManager.SerializeSavedDegreeMode())); - - // Serialize Memory - vector serializedMemory; - serializedMemory = m_standardCalculatorManager.GetSerializedMemory(); - size_t lengthOfSerializedMemory = serializedMemory.size(); - writer->WriteUInt32(static_cast(lengthOfSerializedMemory)); - for (auto data : serializedMemory) - { - writer->WriteInt32(data); - } - - // Serialize Primary Display - vector serializedPrimaryDisplay = m_standardCalculatorManager.GetSerializedPrimaryDisplay(); - writer->WriteUInt32(static_cast(serializedPrimaryDisplay.size())); - for (auto data : serializedPrimaryDisplay) - { - writer->WriteInt32(data); - } - - // For ProgrammerMode - writer->WriteUInt32(static_cast(CurrentRadixType)); - - // Serialize commands of calculator manager - vector serializedCommand = m_standardCalculatorManager.SerializeCommands(); - writer->WriteUInt32(static_cast(serializedCommand.size())); - writer->WriteBytes(ref new Array(serializedCommand.data(), static_cast(serializedCommand.size()))); - - if (IsInError) - { - Utils::SerializeCommandsAndTokens(m_tokens, m_commands, writer); - } - - // Convert viewmodel data in writer to bytes - IBuffer ^ buffer = writer->DetachBuffer(); - DataReader ^ reader = DataReader::FromBuffer(buffer); - Platform::Array ^ viewModelDataAsBytes = ref new Array(buffer->Length); - reader->ReadBytes(viewModelDataAsBytes); - - // Return byte array - return viewModelDataAsBytes; -} - -void StandardCalculatorViewModel::Deserialize(Array ^ state) -{ - // Read byte array into a buffer - DataWriter ^ writer = ref new DataWriter(); - writer->WriteBytes(state); - IBuffer ^ buffer = writer->DetachBuffer(); - - // Read view model data - if (buffer->Length != 0) - { - DataReader ^ reader = DataReader::FromBuffer(buffer); - m_CurrentAngleType = ConvertIntegerToNumbersAndOperatorsEnum(reader->ReadUInt32()); - - IsFToEChecked = reader->ReadBoolean(); - IsCurrentViewPinned = reader->ReadBoolean(); - Command serializedDegreeMode = static_cast(reader->ReadUInt32()); - - m_standardCalculatorManager.SendCommand(serializedDegreeMode); - - // Deserialize Memory - UINT32 memoryDataLength = reader->ReadUInt32(); - vector serializedMemory; - for (unsigned int i = 0; i < memoryDataLength; i++) - { - serializedMemory.push_back(reader->ReadInt32()); - } - m_standardCalculatorManager.DeSerializeMemory(serializedMemory); - - // Serialize Primary Display - UINT32 serializedPrimaryDisplayLength = reader->ReadUInt32(); - vector serializedPrimaryDisplay; - for (unsigned int i = 0; i < serializedPrimaryDisplayLength; i++) - { - serializedPrimaryDisplay.push_back(reader->ReadInt32()); - } - m_standardCalculatorManager.DeSerializePrimaryDisplay(serializedPrimaryDisplay); - - CurrentRadixType = reader->ReadUInt32(); - // Read command data and Deserialize - UINT32 modeldatalength = reader->ReadUInt32(); - Array ^ modelDataAsBytes = ref new Array(modeldatalength); - reader->ReadBytes(modelDataAsBytes); - m_standardCalculatorManager.DeSerializeCommands(vector(modelDataAsBytes->begin(), modelDataAsBytes->end())); - - // After recalculation. If there is an error then - // IsInError should be set synchronously. - if (IsInError) - { - shared_ptr>> commandVector = Utils::DeserializeCommands(reader); - shared_ptr>> tokenVector = Utils::DeserializeTokens(reader); - SetExpressionDisplay(tokenVector, commandVector); - } - } -} - -void StandardCalculatorViewModel::OnPropertyChanged(String ^ propertyname) -{ - if (propertyname == IsScientificPropertyName) - { - if (IsScientific) - { - OnButtonPressed(NumbersAndOperatorsEnum::IsScientificMode); - } - } - else if (propertyname == IsProgrammerPropertyName) - { - if (IsProgrammer) - { - OnButtonPressed(NumbersAndOperatorsEnum::IsProgrammerMode); - } - } - else if (propertyname == IsStandardPropertyName) - { - if (IsStandard) - { - OnButtonPressed(NumbersAndOperatorsEnum::IsStandardMode); - } - } - else if (propertyname == DisplayValuePropertyName) - { - RaisePropertyChanged(CalculationResultAutomationNamePropertyName); - Announcement = GetDisplayUpdatedNarratorAnnouncement(); - } -} - -void StandardCalculatorViewModel::SetCalculatorType(ViewMode targetState) -{ - // Reset error state so that commands caused by the mode change are still - // sent if calc is currently in error state. - IsInError = false; - - // Setting one of these properties to true will set the others to false. - switch (targetState) - { - case ViewMode::Standard: - IsStandard = true; - ResetDisplay(); - SetPrecision(StandardModePrecision); - UpdateMaxIntDigits(); - break; - - case ViewMode::Scientific: - IsScientific = true; - ResetDisplay(); - SetPrecision(ScientificModePrecision); - break; - - case ViewMode::Programmer: - IsProgrammer = true; - ResetDisplay(); - SetPrecision(ProgrammerModePrecision); - break; - } -} - -Platform::String ^ StandardCalculatorViewModel::GetRawDisplayValue() -{ - wstring rawValue; - - LocalizationSettings::GetInstance().RemoveGroupSeparators(DisplayValue->Data(), DisplayValue->Length(), &rawValue); - - return ref new Platform::String(rawValue.c_str()); -} - -// Given a format string, returns a string with the input display value inserted. -// 'format' is a localized string containing a %1 formatting mark where the display value should be inserted. -// 'displayValue' is a localized string containing a numerical value to be displayed to the user. -String ^ StandardCalculatorViewModel::GetLocalizedStringFormat(String ^ format, String ^ displayValue) -{ - String ^ localizedString = ref new String(LocalizationStringUtil::GetLocalizedString(format->Data(), displayValue->Data()).c_str()); - return localizedString; -} - -void StandardCalculatorViewModel::ResetDisplay() -{ - AreHEXButtonsEnabled = false; - CurrentRadixType = (int)RADIX_TYPE::DEC_RADIX; - m_standardCalculatorManager.SetRadix(DEC_RADIX); - ProgModeRadixChange(); -} - -void StandardCalculatorViewModel::SetPrecision(int32_t precision) -{ - m_standardCalculatorManager.SetPrecision(precision); -} - -void StandardCalculatorViewModel::SwitchProgrammerModeBase(RADIX_TYPE radixType) -{ - if (IsInError) - { - m_standardCalculatorManager.SendCommand(Command::CommandCLEAR); - } - - AreHEXButtonsEnabled = (radixType == RADIX_TYPE::HEX_RADIX); - CurrentRadixType = (int)radixType; - m_standardCalculatorManager.SetRadix(radixType); - ProgModeRadixChange(); -} - -void StandardCalculatorViewModel::SetMemorizedNumbersString() -{ - m_standardCalculatorManager.SetMemorizedNumbersString(); -} - -ANGLE_TYPE GetAngleTypeFromCommand(Command command) -{ - switch (command) - { - case Command::CommandDEG: - return ANGLE_DEG; - case Command::CommandRAD: - return ANGLE_RAD; - case Command::CommandGRAD: - return ANGLE_GRAD; - default: - throw ref new Exception(E_FAIL, L"Invalid command type"); - } -} - -void StandardCalculatorViewModel::SaveEditedCommand(_In_ unsigned int tokenPosition, _In_ Command command) -{ - pair token; - bool handleOperand = false; - int nOpCode = static_cast(command); - wstring updatedToken = L""; - - shared_ptr tokenCommand; - IFTPlatformException(m_tokens->GetAt(tokenPosition, &token)); - - unsigned int tokenCommandIndex = token.second; - IFTPlatformException(m_commands->GetAt(tokenCommandIndex, &tokenCommand)); - - if (IsUnaryOp(nOpCode) && command != Command::CommandSIGN) - { - int angleCmd = static_cast(m_standardCalculatorManager.GetCurrentDegreeMode()); - ANGLE_TYPE angleType = GetAngleTypeFromCommand(static_cast(angleCmd)); - - if (IsTrigOp(nOpCode)) - { - shared_ptr spUnaryCommand = dynamic_pointer_cast(tokenCommand); - spUnaryCommand->SetCommands(angleCmd, nOpCode); - } - else - { - shared_ptr spUnaryCommand = dynamic_pointer_cast(tokenCommand); - spUnaryCommand->SetCommand(nOpCode); - } - - switch (nOpCode) - { - case static_cast(Command::CommandASIN): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSIN), true, angleType); - break; - case static_cast(Command::CommandACOS): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOS), true, angleType); - break; - case static_cast(Command::CommandATAN): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTAN), true, angleType); - break; - case static_cast(Command::CommandASINH): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSINH), true, angleType); - break; - case static_cast(Command::CommandACOSH): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOSH), true, angleType); - break; - case static_cast(Command::CommandATANH): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTANH), true, angleType); - break; - case static_cast(Command::CommandPOWE): - updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandLN), true, angleType); - break; - default: - updatedToken = CCalcEngine::OpCodeToUnaryString(nOpCode, false, angleType); - } - if ((token.first.length() > 0) && (token.first[token.first.length() - 1] == L'(')) - { - wstring chOpenBrace = L"("; - updatedToken.append(chOpenBrace); - } - } - else if (IsBinOp(nOpCode)) - { - shared_ptr spBinaryCommand = dynamic_pointer_cast(tokenCommand); - spBinaryCommand->SetCommand(nOpCode); - updatedToken = CCalcEngine::OpCodeToString(nOpCode); - } - else if (IsOpnd(nOpCode) || command == Command::CommandBACK) - { - HandleUpdatedOperandData(command); - handleOperand = true; - } - else if (command == Command::CommandSIGN) - { - if (tokenCommand->GetCommandType() == CommandType::UnaryCommand) - { - shared_ptr spSignCommand = make_shared(nOpCode); - IFTPlatformException(m_commands->InsertAt(tokenCommandIndex + 1, spSignCommand)); - } - else - { - shared_ptr spOpndCommand = dynamic_pointer_cast(tokenCommand); - spOpndCommand->ToggleSign(); - updatedToken = spOpndCommand->GetToken(m_standardCalculatorManager.DecimalSeparator()); - } - IsOperandUpdatedUsingViewModel = true; - } - - if (!handleOperand) - { - IFTPlatformException(m_commands->SetAt(tokenCommandIndex, tokenCommand)); - - pair selectedToken; - IFTPlatformException(m_tokens->GetAt(tokenPosition, &selectedToken)); - selectedToken.first = updatedToken; - IFTPlatformException(m_tokens->SetAt(tokenPosition, selectedToken)); - - DisplayExpressionToken ^ displayExpressionToken = ExpressionTokens->GetAt(tokenPosition); - displayExpressionToken->Token = ref new Platform::String(updatedToken.c_str()); - - // Special casing - if (command == Command::CommandSIGN && tokenCommand->GetCommandType() == CommandType::UnaryCommand) - { - IsEditingEnabled = false; - Recalculate(); - } - } -} - -void StandardCalculatorViewModel::Recalculate(bool fromHistory) -{ - // Recalculate - Command currentDegreeMode = m_standardCalculatorManager.GetCurrentDegreeMode(); - shared_ptr>> savedCommands = make_shared>>(); - - vector currentCommands; - unsigned int commandListCount; - m_commands->GetSize(&commandListCount); - for (unsigned int i = 0; i < commandListCount; i++) - { - shared_ptr command; - IFTPlatformException(m_commands->GetAt(i, &command)); - - savedCommands->Append(command); - CommandType commandType = command->GetCommandType(); - - if (commandType == CommandType::UnaryCommand) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - shared_ptr> unaryCommands = spCommand->GetCommands(); - unsigned int unaryCommandCount; - unaryCommands->GetSize(&unaryCommandCount); - - int nUCode; - for (unsigned int j = 0; j < unaryCommandCount; ++j) - { - IFTPlatformException(unaryCommands->GetAt(j, &nUCode)); - currentCommands.push_back(nUCode); - } - } - - if (commandType == CommandType::BinaryCommand) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - currentCommands.push_back(spCommand->GetCommand()); - } - - if (commandType == CommandType::Parentheses) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - currentCommands.push_back(spCommand->GetCommand()); - } - - if (commandType == CommandType::OperandCommand) - { - shared_ptr spCommand = dynamic_pointer_cast(command); - shared_ptr> opndCommands = spCommand->GetCommands(); - unsigned int opndCommandCount; - opndCommands->GetSize(&opndCommandCount); - bool fNeedIDCSign = spCommand->IsNegative(); - - int nOCode; - for (unsigned int j = 0; j < opndCommandCount; ++j) - { - IFTPlatformException(opndCommands->GetAt(j, &nOCode)); - currentCommands.push_back(nOCode); - - if (fNeedIDCSign && nOCode != IDC_0) - { - currentCommands.push_back(static_cast(CalculationManager::Command::CommandSIGN)); - fNeedIDCSign = false; - } - } - } - } - shared_ptr>> savedTokens = make_shared>>(); - - unsigned int tokenCount; - IFTPlatformException(m_tokens->GetSize(&tokenCount)); - - for (unsigned int i = 0; i < tokenCount; ++i) - { - pair currentToken; - IFTPlatformException(m_tokens->GetAt(i, ¤tToken)); - savedTokens->Append(currentToken); - } - - m_standardCalculatorManager.Reset(false); - if (IsScientific) - { - m_standardCalculatorManager.SendCommand(Command::ModeScientific); - } - - if (IsFToEChecked) - { - m_standardCalculatorManager.SendCommand(Command::CommandFE); - } - - m_standardCalculatorManager.SendCommand(currentDegreeMode); - size_t currentCommandsSize = currentCommands.size(); - for (size_t i = 0; i < currentCommandsSize; i++) - { - m_standardCalculatorManager.SendCommand(static_cast(currentCommands[i])); - } - - if (fromHistory) // This is for the cases where the expression is loaded from history - { - // To maintain F-E state of the engine, as the last operand hasn't reached engine by now - m_standardCalculatorManager.SendCommand(Command::CommandFE); - m_standardCalculatorManager.SendCommand(Command::CommandFE); - } - - // After recalculation. If there is an error then - // IsInError should be set synchronously. - if (IsInError) - { - SetExpressionDisplay(savedTokens, savedCommands); - } -} - -CommandType StandardCalculatorViewModel::GetSelectedTokenType(_In_ unsigned int tokenPosition) -{ - pair token; - shared_ptr tokenCommand; - IFTPlatformException(m_tokens->GetAt(tokenPosition, &token)); - - unsigned int tokenCommandIndex = token.second; - IFTPlatformException(m_commands->GetAt(tokenCommandIndex, &tokenCommand)); - - return tokenCommand->GetCommandType(); -} - -bool StandardCalculatorViewModel::IsOpnd(int nOpCode) -{ - static Command opnd[] = { Command::Command0, Command::Command1, Command::Command2, Command::Command3, Command::Command4, Command::Command5, - Command::Command6, Command::Command7, Command::Command8, Command::Command9, Command::CommandPNT }; - - for (unsigned int i = 0; i < size(opnd); i++) - { - if (nOpCode == static_cast(opnd[i])) - { - return true; - } - } - return false; -} - -bool StandardCalculatorViewModel::IsUnaryOp(int nOpCode) -{ - static Command unaryOp[] = { Command::CommandSQRT, Command::CommandFAC, Command::CommandSQR, Command::CommandLOG, - Command::CommandPOW10, Command::CommandPOWE, Command::CommandLN, Command::CommandREC, - Command::CommandSIGN, Command::CommandSINH, Command::CommandASINH, Command::CommandCOSH, - Command::CommandACOSH, Command::CommandTANH, Command::CommandATANH, Command::CommandCUB }; - - for (unsigned int i = 0; i < size(unaryOp); i++) - { - if (nOpCode == static_cast(unaryOp[i])) - { - return true; - } - } - - if (IsTrigOp(nOpCode)) - { - return true; - } - - return false; -} - -bool StandardCalculatorViewModel::IsTrigOp(int nOpCode) -{ - static Command trigOp[] = { - Command::CommandSIN, Command::CommandCOS, Command::CommandTAN, Command::CommandASIN, Command::CommandACOS, Command::CommandATAN - }; - - for (unsigned int i = 0; i < size(trigOp); i++) - { - if (nOpCode == static_cast(trigOp[i])) - { - return true; - } - } - return false; -} - -bool StandardCalculatorViewModel::IsBinOp(int nOpCode) -{ - static Command binOp[] = { Command::CommandADD, Command::CommandSUB, Command::CommandMUL, Command::CommandDIV, - Command::CommandEXP, Command::CommandROOT, Command::CommandMOD, Command::CommandPWR }; - - for (unsigned int i = 0; i < size(binOp); i++) - { - if (nOpCode == static_cast(binOp[i])) - { - return true; - } - } - return false; -} - -bool StandardCalculatorViewModel::IsRecoverableCommand(int nOpCode) -{ - if (IsOpnd(nOpCode)) - { - return true; - } - - // Programmer mode, bit flipping - int minBinPos = static_cast(Command::CommandBINEDITSTART); - int maxBinPos = static_cast(Command::CommandBINEDITEND); - if (minBinPos <= nOpCode && nOpCode <= maxBinPos) - { - return true; - } - - static Command recoverableCommands[] = { Command::CommandA, Command::CommandB, Command::CommandC, Command::CommandD, Command::CommandE, Command::CommandF }; - - for (unsigned int i = 0; i < size(recoverableCommands); i++) - { - if (nOpCode == static_cast(recoverableCommands[i])) - { - return true; - } - } - return false; -} - -size_t StandardCalculatorViewModel::LengthWithoutPadding(wstring str) -{ - size_t count = 0; - for (size_t i = 0; i < str.length(); i++) - { - if (str[i] != L' ') - { - count++; - } - } - return count; -} - -wstring StandardCalculatorViewModel::AddPadding(wstring binaryString) -{ - if (LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(binaryString) == L"0") - { - return binaryString; - } - size_t pad = 4 - LengthWithoutPadding(binaryString) % 4; - if (pad == 4) - { - pad = 0; - } - wstring padString = L""; - for (size_t i = 0; i < pad; i++) - { - padString += L"0"; - } - return padString + binaryString; -} - -void StandardCalculatorViewModel::UpdateProgrammerPanelDisplay() -{ - wstring hexDisplayString; - wstring decimalDisplayString; - wstring octalDisplayString; - wstring binaryDisplayString; - if (!IsInError) - { - // we want the precision to be set to maximum value so that the autoconversions result as desired - int32_t precision = 64; - if (m_standardCalculatorManager.GetResultForRadix(16, precision) == L"") - { - hexDisplayString = DisplayValue->Data(); - decimalDisplayString = DisplayValue->Data(); - octalDisplayString = DisplayValue->Data(); - binaryDisplayString = DisplayValue->Data(); - } - else - { - hexDisplayString = m_standardCalculatorManager.GetResultForRadix(16, precision); - decimalDisplayString = m_standardCalculatorManager.GetResultForRadix(10, precision); - octalDisplayString = m_standardCalculatorManager.GetResultForRadix(8, precision); - binaryDisplayString = m_standardCalculatorManager.GetResultForRadix(2, precision); - } - } - const auto& localizer = LocalizationSettings::GetInstance(); - binaryDisplayString = AddPadding(binaryDisplayString); - - localizer.LocalizeDisplayValue(&hexDisplayString); - localizer.LocalizeDisplayValue(&decimalDisplayString); - localizer.LocalizeDisplayValue(&octalDisplayString); - localizer.LocalizeDisplayValue(&binaryDisplayString); - - HexDisplayValue = Utils::LRO + ref new Platform::String(hexDisplayString.c_str()) + Utils::PDF; - DecimalDisplayValue = Utils::LRO + ref new Platform::String(decimalDisplayString.c_str()) + Utils::PDF; - OctalDisplayValue = Utils::LRO + ref new Platform::String(octalDisplayString.c_str()) + Utils::PDF; - BinaryDisplayValue = Utils::LRO + ref new Platform::String(binaryDisplayString.c_str()) + Utils::PDF; - HexDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedHexaDecimalAutomationFormat, GetNarratorStringReadRawNumbers(HexDisplayValue)); - DecDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedDecimalAutomationFormat, DecimalDisplayValue); - OctDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedOctalAutomationFormat, GetNarratorStringReadRawNumbers(OctalDisplayValue)); - BinDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedBinaryAutomationFormat, GetNarratorStringReadRawNumbers(BinaryDisplayValue)); -} - -void StandardCalculatorViewModel::SwitchAngleType(NumbersAndOperatorsEnum num) -{ - OnButtonPressed(num); -} - -NumbersAndOperatorsEnum StandardCalculatorViewModel::ConvertIntegerToNumbersAndOperatorsEnum(unsigned int parameter) -{ - NumbersAndOperatorsEnum angletype; - switch (parameter) - { - case 321: - angletype = NumbersAndOperatorsEnum::Degree; - break; - case 322: - angletype = NumbersAndOperatorsEnum::Radians; - break; - case 323: - angletype = NumbersAndOperatorsEnum::Grads; - break; - default: - angletype = NumbersAndOperatorsEnum::Degree; - }; - return angletype; -} - -void StandardCalculatorViewModel::UpdateOperand(int pos, String ^ text) -{ - pair p; - m_tokens->GetAt(pos, &p); - - String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(text->Data()); - p.first = englishString->Data(); - - int commandPos = p.second; - shared_ptr exprCmd; - m_commands->GetAt(commandPos, &exprCmd); - auto operandCommand = std::dynamic_pointer_cast(exprCmd); - - if (operandCommand != nullptr) - { - shared_ptr> commands = make_shared>(); - size_t length = p.first.length(); - if (length > 0) - { - int num = 0; - for (unsigned int i = 0; i < length; ++i) - { - if (p.first[i] == L'.') - { - num = static_cast(Command::CommandPNT); - } - else if (p.first[i] == L'e') - { - num = static_cast(Command::CommandEXP); - } - else if (p.first[i] == L'-') - { - num = static_cast(Command::CommandSIGN); - - if (i == 0) - { - shared_ptr spOpndCommand = dynamic_pointer_cast(exprCmd); - if (!spOpndCommand->IsNegative()) - { - spOpndCommand->ToggleSign(); - } - continue; - } - } - else - { - num = static_cast(p.first[i]) - ASCII_0; - num += IDC_0; - if (num == static_cast(Command::CommandMPLUS)) - { - continue; - } - } - commands->Append(num); - } - } - else - { - commands->Append(0); - } - operandCommand->SetCommands(commands); - } -} - -void StandardCalculatorViewModel::UpdatecommandsInRecordingMode() -{ - vector savedCommands = m_standardCalculatorManager.GetSavedCommands(); - shared_ptr> commands = make_shared>(); - bool isDecimal = false; - bool isNegative = false; - bool isExpMode = false; - bool ePlusMode = false; - bool eMinusMode = false; - - int num = 0; - Command val; - for (unsigned int i = 0; i < savedCommands.size(); ++i) - { - val = safe_cast(savedCommands[i]); - num = static_cast(val); - if (val == Command::CommandSIGN) - { - isNegative = true; - continue; - } - else if ((val >= Command::Command0 && val <= Command::Command9)) - { - } - else if (val == Command::CommandPNT) - { - isDecimal = true; - } - else if (val == Command::CommandEXP) - { - isExpMode = true; - } - else if (isExpMode && !ePlusMode && (val == Command::CommandMPLUS)) - { - ePlusMode = true; - continue; - } - else if (isExpMode && !eMinusMode && (val == Command::CommandMMINUS)) - { - eMinusMode = true; - continue; - } - else - { - // Reset all vars - isDecimal = false; - isNegative = false; - isExpMode = false; - ePlusMode = false; - eMinusMode = false; - commands->Clear(); - continue; - } - commands->Append(num); - } - - unsigned int size = 0; - commands->GetSize(&size); - if (size > 0) - { - shared_ptr sp = make_shared(commands, isNegative, isDecimal, isExpMode); - m_commands->Append(sp); - } - Recalculate(); -} - -void StandardCalculatorViewModel::OnMaxDigitsReached() -{ - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MaxDigitsReachedFormat, m_localizedMaxDigitsReachedAutomationFormat, m_CalculationResultAutomationName->Data()); - - Announcement = CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(announcement); -} - -void StandardCalculatorViewModel::OnBinaryOperatorReceived() -{ - Announcement = GetDisplayUpdatedNarratorAnnouncement(); -} - -NarratorAnnouncement ^ StandardCalculatorViewModel::GetDisplayUpdatedNarratorAnnouncement() -{ - String ^ announcement; - if (m_feedbackForButtonPress == nullptr || m_feedbackForButtonPress->IsEmpty()) - { - announcement = m_CalculationResultAutomationName; - } - else - { - announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::ButtonPressFeedbackFormat, - m_localizedButtonPressFeedbackAutomationFormat, - m_CalculationResultAutomationName->Data(), - m_feedbackForButtonPress->Data()); - } - - // Make sure we don't accidentally repeat an announcement. - m_feedbackForButtonPress = nullptr; - - return CalculatorAnnouncement::GetDisplayUpdatedAnnouncement(announcement); -} diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h deleted file mode 100644 index 5a1a4dea..00000000 --- a/src/CalcViewModel/StandardCalculatorViewModel.h +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "Common/Automation/NarratorAnnouncement.h" -#include "Common/DisplayExpressionToken.h" -#include "Common/CalculatorDisplay.h" -#include "Common/EngineResourceProvider.h" -#include "Common/CalculatorButtonUser.h" -#include "HistoryViewModel.h" -#include "MemoryItemViewModel.h" - -namespace CalculatorFunctionalTests -{ - class HistoryTests; -} - -namespace CalculatorUnitTests -{ - class MultiWindowUnitTests; - class TimerTests; -} - -namespace CalculatorApp -{ - namespace WS = Windows::System; - namespace CM = CalculationManager; - - namespace ViewModel - { -#define ASCII_0 48 - public - delegate void HideMemoryClickedHandler(); - public - delegate void ProgModeRadixChangeHandler(); - - [Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - public: - StandardCalculatorViewModel(); - void UpdateOperand(int pos, Platform::String ^ text); - void UpdatecommandsInRecordingMode(); - int GetBitLengthType(); - int GetNumberBase(); - - OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DisplayValue); - OBSERVABLE_PROPERTY_RW(HistoryViewModel ^, HistoryVM); - OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError); - OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DisplayStringExpression); - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, ExpressionTokens); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DecimalDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String ^, HexDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String ^, OctalDisplayValue); - OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, BinaryDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String ^, HexDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DecDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, OctDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, BinDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(bool, IsBinaryOperatorEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsUnaryOperatorEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsNegateEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsCurrentViewPinned); - OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector ^, MemorizedNumbers); - OBSERVABLE_NAMED_PROPERTY_RW(bool, IsMemoryEmpty); - OBSERVABLE_PROPERTY_RW(bool, IsFToEChecked); - OBSERVABLE_PROPERTY_RW(bool, IsFToEEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsHyperbolicChecked); - OBSERVABLE_PROPERTY_RW(bool, AreHEXButtonsEnabled); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CalculationResultAutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CalculationExpressionAutomationName); - OBSERVABLE_PROPERTY_RW(bool, IsShiftProgrammerChecked); - OBSERVABLE_PROPERTY_RW(bool, IsQwordEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsDwordEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsWordEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsByteEnabled); - OBSERVABLE_PROPERTY_RW(int, CurrentRadixType); - OBSERVABLE_PROPERTY_RW(bool, AreTokensUpdated); - OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled); - OBSERVABLE_PROPERTY_RW(bool, AreProgrammerRadixOperatorsEnabled); - OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement ^, Announcement); - OBSERVABLE_PROPERTY_R(unsigned int, OpenParenthesisCount); - - COMMAND_FOR_METHOD(CopyCommand, StandardCalculatorViewModel::OnCopyCommand); - COMMAND_FOR_METHOD(PasteCommand, StandardCalculatorViewModel::OnPasteCommand); - COMMAND_FOR_METHOD(ButtonPressed, StandardCalculatorViewModel::OnButtonPressed); - COMMAND_FOR_METHOD(ClearMemoryCommand, StandardCalculatorViewModel::OnClearMemoryCommand); - COMMAND_FOR_METHOD(MemoryItemPressed, StandardCalculatorViewModel::OnMemoryItemPressed); - COMMAND_FOR_METHOD(MemoryAdd, StandardCalculatorViewModel::OnMemoryAdd); - COMMAND_FOR_METHOD(MemorySubtract, StandardCalculatorViewModel::OnMemorySubtract); - - event HideMemoryClickedHandler ^ HideMemoryClicked; - event ProgModeRadixChangeHandler ^ ProgModeRadixChange; - - property bool IsShiftChecked - { - bool get() - { - return m_isShiftChecked; - } - void set(bool value) - { - if (m_isShiftChecked != value) - { - m_isShiftChecked = value; - RaisePropertyChanged(L"IsShiftChecked"); - } - } - } - - property bool IsBitFlipChecked - { - bool get() - { - return m_isBitFlipChecked; - } - void set(bool value) - { - if (m_isBitFlipChecked != value) - { - m_isBitFlipChecked = value; - IsBinaryBitFlippingEnabled = IsProgrammer && m_isBitFlipChecked; - AreProgrammerRadixOperatorsEnabled = IsProgrammer && !m_isBitFlipChecked; - RaisePropertyChanged(L"IsBitFlipChecked"); - } - } - } - - property bool IsBinaryBitFlippingEnabled - { - bool get() - { - return m_isBinaryBitFlippingEnabled; - } - void set(bool value) - { - if (m_isBinaryBitFlippingEnabled != value) - { - m_isBinaryBitFlippingEnabled = value; - RaisePropertyChanged(L"IsBinaryBitFlippingEnabled"); - } - } - } - - property bool IsStandard - { - bool get() - { - return m_isStandard; - } - void set(bool value) - { - if (m_isStandard != value) - { - m_isStandard = value; - if (value) - { - IsScientific = false; - IsProgrammer = false; - } - RaisePropertyChanged(L"IsStandard"); - } - } - } - - property bool IsScientific - { - bool get() - { - return m_isScientific; - } - void set(bool value) - { - if (m_isScientific != value) - { - m_isScientific = value; - if (value) - { - IsStandard = false; - IsProgrammer = false; - } - RaisePropertyChanged(L"IsScientific"); - } - } - } - - property bool IsProgrammer - { - bool get() - { - return m_isProgrammer; - } - void set(bool value) - { - if (m_isProgrammer != value) - { - m_isProgrammer = value; - if (!m_isProgrammer) - { - IsBitFlipChecked = false; - } - IsBinaryBitFlippingEnabled = m_isProgrammer && IsBitFlipChecked; - AreProgrammerRadixOperatorsEnabled = m_isProgrammer && !IsBitFlipChecked; - if (value) - { - IsStandard = false; - IsScientific = false; - } - RaisePropertyChanged(L"IsProgrammer"); - } - } - } - - property bool IsEditingEnabled - { - bool get() - { - return m_isEditingEnabled; - } - void set(bool value) - { - if (m_isEditingEnabled != value) - { - // Numbers::Common::KeyboardShortcutManager::IsCalculatorInEditingMode = value; - m_isEditingEnabled = value; - bool currentEditToggleValue = !m_isEditingEnabled; - IsBinaryOperatorEnabled = currentEditToggleValue; - IsUnaryOperatorEnabled = currentEditToggleValue; - IsOperandEnabled = currentEditToggleValue; - IsNegateEnabled = currentEditToggleValue; - IsDecimalEnabled = currentEditToggleValue; - RaisePropertyChanged(L"IsEditingEnabled"); - } - } - } - - property bool IsEngineRecording - { - bool get() - { - return m_standardCalculatorManager.IsEngineRecording(); - } - } - - property bool IsOperandEnabled - { - bool get() - { - return m_isOperandEnabled; - } - void set(bool value) - { - if (m_isOperandEnabled != value) - { - m_isOperandEnabled = value; - IsDecimalEnabled = value; - AreHEXButtonsEnabled = IsProgrammer; - IsFToEEnabled = value; - RaisePropertyChanged(L"IsOperandEnabled"); - } - } - } - - property int TokenPosition - { - int get() - { - return m_tokenPosition; - } - void set(int value) - { - m_tokenPosition = value; - } - } - - property Platform::String^ SelectedExpressionLastData - { - Platform::String^ get() { return m_selectedExpressionLastData; } - void set(Platform::String^ value) { m_selectedExpressionLastData = value; } - } - - property bool KeyPressed - { - bool get() - { - return m_keyPressed; - } - void set(bool value) - { - m_keyPressed = value; - } - } - - property bool IsOperandUpdatedUsingViewModel - { - bool get() - { - return m_operandUpdated; - } - void set(bool value) - { - m_operandUpdated = value; - } - } - - property bool IsOperandTextCompletelySelected - { - bool get() - { - return m_completeTextSelection; - } - void set(bool value) - { - m_completeTextSelection = value; - } - } - - internal : void OnPaste(Platform::String ^ pastedString, CalculatorApp::Common::ViewMode mode); - void OnCopyCommand(Platform::Object ^ parameter); - void OnPasteCommand(Platform::Object ^ parameter); - - NumbersAndOperatorsEnum MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate); - - // Memory feature related methods. They are internal because they need to called from the MainPage code-behind - void OnMemoryButtonPressed(); - void OnMemoryItemPressed(Platform::Object ^ memoryItemPosition); - void OnMemoryAdd(Platform::Object ^ memoryItemPosition); - void OnMemorySubtract(Platform::Object ^ memoryItemPosition); - void OnMemoryClear(_In_ Platform::Object ^ memoryItemPosition); - void OnPinUnpinCommand(Platform::Object ^ parameter); - - void SetPrimaryDisplay(_In_ std::wstring const& displayString, _In_ bool isError); - void DisplayPasteError(); - void SetTokens(_Inout_ std::shared_ptr>> const& tokens); - void SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands); - void SetHistoryExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands); - void SetParenthesisCount(_In_ unsigned int parenthesisCount); - void SetOpenParenthesisCountNarratorAnnouncement(); - void OnNoRightParenAdded(); - void SetNoParenAddedNarratorAnnouncement(); - void OnMaxDigitsReached(); - void OnBinaryOperatorReceived(); - void OnMemoryItemChanged(unsigned int indexOfMemory); - - Platform::Array ^ Serialize(); - void Deserialize(Platform::Array ^ state); - - Platform::String ^ GetLocalizedStringFormat(Platform::String ^ format, Platform::String ^ displayValue); - void OnPropertyChanged(Platform::String ^ propertyname); - void SetCalculatorType(CalculatorApp::Common::ViewMode targetState); - - Platform::String ^ GetRawDisplayValue(); - void Recalculate(bool fromHistory = false); - bool IsOperator(CalculationManager::Command cmdenum); - void FtoEButtonToggled(); - void SwitchProgrammerModeBase(RADIX_TYPE calculatorBase); - void SetMemorizedNumbersString(); - void SwitchAngleType(NumbersAndOperatorsEnum num); - void ResetDisplay(); - RADIX_TYPE GetCurrentRadixType() - { - return (RADIX_TYPE)m_CurrentRadixType; - } - void SetPrecision(int32_t precision); - void UpdateMaxIntDigits() - { - m_standardCalculatorManager.UpdateMaxIntDigits(); - } - NumbersAndOperatorsEnum GetCurrentAngleType() - { - return m_CurrentAngleType; - } - - private: - void SetMemorizedNumbers(const std::vector& memorizedNumbers); - void UpdateProgrammerPanelDisplay(); - void HandleUpdatedOperandData(CalculationManager::Command cmdenum); - NumbersAndOperatorsEnum ConvertIntegerToNumbersAndOperatorsEnum(unsigned int parameter); - NumbersAndOperatorsEnum m_CurrentAngleType; - wchar_t m_decimalSeparator; - CalculatorDisplay m_calculatorDisplay; - CalculatorApp::EngineResourceProvider m_resourceProvider; - CalculationManager::CalculatorManager m_standardCalculatorManager; - Platform::String ^ m_expressionAutomationNameFormat; - Platform::String ^ m_localizedCalculationResultAutomationFormat; - Platform::String ^ m_localizedCalculationResultDecimalAutomationFormat; - Platform::String ^ m_localizedHexaDecimalAutomationFormat; - Platform::String ^ m_localizedDecimalAutomationFormat; - Platform::String ^ m_localizedOctalAutomationFormat; - Platform::String ^ m_localizedBinaryAutomationFormat; - Platform::String ^ m_localizedMaxDigitsReachedAutomationFormat; - Platform::String ^ m_localizedButtonPressFeedbackAutomationFormat; - Platform::String ^ m_localizedMemorySavedAutomationFormat; - Platform::String ^ m_localizedMemoryItemChangedAutomationFormat; - Platform::String ^ m_localizedMemoryItemClearedAutomationFormat; - Platform::String ^ m_localizedMemoryCleared; - Platform::String ^ m_localizedOpenParenthesisCountChangedAutomationFormat; - Platform::String ^ m_localizedNoRightParenthesisAddedFormat; - - bool m_pinned; - bool m_isOperandEnabled; - bool m_isEditingEnabled; - bool m_isStandard; - bool m_isScientific; - bool m_isProgrammer; - bool m_isBinaryBitFlippingEnabled; - bool m_isBitFlipChecked; - bool m_isShiftChecked; - bool m_isRtlLanguage; - int m_tokenPosition; - bool m_keyPressed; - bool m_operandUpdated; - bool m_completeTextSelection; - bool m_isLastOperationHistoryLoad; - Platform::String ^ m_selectedExpressionLastData; - Common::DisplayExpressionToken ^ m_selectedExpressionToken; - - Platform::String ^ LocalizeDisplayValue(_In_ std::wstring const& displayValue, _In_ bool isError); - Platform::String - ^ CalculateNarratorDisplayValue(_In_ std::wstring const& displayValue, _In_ Platform::String ^ localizedDisplayValue, _In_ bool isError); - CalculatorApp::Common::Automation::NarratorAnnouncement ^ GetDisplayUpdatedNarratorAnnouncement(); - Platform::String ^ GetCalculatorExpressionAutomationName(); - Platform::String ^ GetNarratorStringReadRawNumbers(_In_ Platform::String ^ localizedDisplayValue); - - CalculationManager::Command ConvertToOperatorsEnum(NumbersAndOperatorsEnum operation); - void DisableButtons(CalculationManager::CommandType selectedExpressionCommandType); - - Platform::String ^ m_feedbackForButtonPress; - void OnButtonPressed(Platform::Object ^ parameter); - void OnClearMemoryCommand(Platform::Object ^ parameter); - std::wstring AddPadding(std::wstring); - size_t LengthWithoutPadding(std::wstring); - - std::shared_ptr>> m_tokens; - std::shared_ptr>> m_commands; - - // Token types - bool IsUnaryOp(int nOpCode); - bool IsBinOp(int nOpcode); - bool IsTrigOp(int nOpCode); - bool IsOpnd(int nOpCode); - bool IsRecoverableCommand(int nOpCode); - - CalculationManager::CommandType GetSelectedTokenType(_In_ unsigned int); - void SaveEditedCommand(_In_ unsigned int index, _In_ CalculationManager::Command command); - - bool IsViewPinned(); - void SetViewPinnedState(bool pinned); - - friend class CalculatorDisplay; - friend class CalculatorFunctionalTests::HistoryTests; - friend class CalculatorUnitTests::MultiWindowUnitTests; - friend class CalculatorUnitTests::TimerTests; - }; - } -} diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp deleted file mode 100644 index 7c48e7c4..00000000 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ /dev/null @@ -1,1071 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "UnitConverterViewModel.h" -#include "CalcManager/Header Files/EngineStrings.h" -#include "Common/CalculatorButtonPressedEventArgs.h" -#include "Common/CopyPasteManager.h" -#include "Common/LocalizationStringUtil.h" -#include "Common/LocalizationService.h" -#include "Common/LocalizationSettings.h" -#include "Common/TraceLogger.h" -#include "DataLoaders/CurrencyHttpClient.h" -#include "DataLoaders/CurrencyDataLoader.h" -#include "DataLoaders/UnitConverterDataLoader.h" - -using namespace CalculatorApp; -using namespace CalculatorApp::Common; -using namespace CalculatorApp::Common::Automation; -using namespace CalculatorApp::ViewModel; -using namespace concurrency; -using namespace Platform; -using namespace Platform::Collections; -using namespace std; -using namespace Windows::Foundation; -using namespace Windows::Globalization::NumberFormatting; -using namespace Windows::System; -using namespace Windows::System::Threading; -using namespace Windows::System::UserProfile; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Automation::Peers; -using namespace Windows::ApplicationModel::Resources; -using namespace Windows::Storage; - -constexpr int EXPECTEDVIEWMODELDATATOKENS = 8; - -// interval is in 100 nanosecond units -constexpr unsigned int TIMER_INTERVAL_IN_MS = 10000; - -#ifdef UNIT_TESTS -#define TIMER_CALLBACK_CONTEXT CallbackContext::Any -#else -#define TIMER_CALLBACK_CONTEXT CallbackContext::Same -#endif - -const TimeSpan SUPPLEMENTARY_VALUES_INTERVAL = { 10 * TIMER_INTERVAL_IN_MS }; - -static Unit ^ EMPTY_UNIT = ref new Unit(UCM::EMPTY_UNIT); - -constexpr size_t UNIT_LIST = 0; -constexpr size_t SELECTED_SOURCE_UNIT = 1; -constexpr size_t SELECTED_TARGET_UNIT = 2; - -// x millisecond delay before we consider conversion to be final -constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000; -const wregex regexTrimSpacesStart = wregex(L"^\\s+"); -const wregex regexTrimSpacesEnd = wregex(L"\\s+$"); - -namespace -{ - StringReference CurrentCategoryPropertyName(L"CurrentCategory"); - StringReference Unit1AutomationNamePropertyName(L"Unit1AutomationName"); - StringReference Unit2AutomationNamePropertyName(L"Unit2AutomationName"); - StringReference Unit1PropertyName(L"Unit1"); - StringReference Unit2PropertyName(L"Unit2"); - StringReference Value1PropertyName(L"Value1"); - StringReference Value2PropertyName(L"Value2"); - StringReference Value1ActivePropertyName(L"Value1Active"); - StringReference Value2ActivePropertyName(L"Value2Active"); - StringReference Value1AutomationNamePropertyName(L"Value1AutomationName"); - StringReference Value2AutomationNamePropertyName(L"Value2AutomationName"); - StringReference CurrencySymbol1PropertyName(L"CurrencySymbol1"); - StringReference CurrencySymbol2PropertyName(L"CurrencySymbol2"); - StringReference CurrencySymbolVisibilityPropertyName(L"CurrencySymbolVisibility"); - StringReference SupplementaryVisibilityPropertyName(L"SupplementaryVisibility"); -} - -namespace CalculatorApp::ViewModel::UnitConverterResourceKeys -{ - StringReference ValueFromFormat(L"Format_ValueFrom"); - StringReference ValueFromDecimalFormat(L"Format_ValueFrom_Decimal"); - StringReference ValueToFormat(L"Format_ValueTo"); - StringReference ConversionResultFormat(L"Format_ConversionResult"); - StringReference InputUnit_Name(L"InputUnit_Name"); - StringReference OutputUnit_Name(L"OutputUnit_Name"); - StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached"); - StringReference UpdatingCurrencyRates(L"UpdatingCurrencyRates"); - StringReference CurrencyRatesUpdated(L"CurrencyRatesUpdated"); - StringReference CurrencyRatesUpdateFailed(L"CurrencyRatesUpdateFailed"); -} - -UnitConverterViewModel::UnitConverterViewModel(const shared_ptr& model) - : m_model(model) - , m_resettingTimer(false) - , m_value1cp(ConversionParameter::Source) - , m_Value1Active(true) - , m_Value2Active(false) - , m_Value1("0") - , m_Value2("0") - , m_valueToUnlocalized(L"0") - , m_valueFromUnlocalized(L"0") - , m_relocalizeStringOnSwitch(false) - , m_Categories(ref new Vector()) - , m_Units(ref new Vector()) - , m_SupplementaryResults(ref new Vector) - , m_IsDropDownOpen(false) - , m_IsDropDownEnabled(true) - , m_IsCurrencyLoadingVisible(false) - , m_isCurrencyDataLoaded(false) - , m_lastAnnouncedFrom(L"") - , m_lastAnnouncedTo(L"") - , m_lastAnnouncedConversionResult(L"") - , m_isValue1Updating(false) - , m_isValue2Updating(false) - , m_Announcement(nullptr) - , m_Mode(ViewMode::None) - , m_CurrencySymbol1(L"") - , m_CurrencySymbol2(L"") - , m_IsCurrencyCurrentCategory(false) - , m_CurrencyRatioEquality(L"") - , m_CurrencyRatioEqualityAutomationName(L"") - , m_isInputBlocked(false) - , m_CurrencyDataLoadFailed(false) -{ - m_model->SetViewModelCallback(make_shared(this)); - m_model->SetViewModelCurrencyCallback(make_shared(this)); - m_decimalFormatter = LocalizationService::GetRegionalSettingsAwareDecimalFormatter(); - m_decimalFormatter->FractionDigits = 0; - m_decimalFormatter->IsGrouped = true; - m_decimalSeparator = LocalizationSettings::GetInstance().GetDecimalSeparator(); - - m_currencyFormatter = LocalizationService::GetRegionalSettingsAwareCurrencyFormatter(); - m_currencyFormatter->IsGrouped = true; - m_currencyFormatter->Mode = CurrencyFormatterMode::UseCurrencyCode; - m_currencyFormatter->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown); - m_currencyMaxFractionDigits = m_currencyFormatter->FractionDigits; - - auto resourceLoader = AppResourceProvider::GetInstance(); - m_localizedValueFromFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueFromFormat); - m_localizedValueToFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueToFormat); - m_localizedConversionResultFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ConversionResultFormat); - m_localizedValueFromDecimalFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueFromDecimalFormat); - m_localizedInputUnitName = resourceLoader.GetResourceString(UnitConverterResourceKeys::InputUnit_Name); - m_localizedOutputUnitName = resourceLoader.GetResourceString(UnitConverterResourceKeys::OutputUnit_Name); - - Unit1AutomationName = m_localizedInputUnitName; - Unit2AutomationName = m_localizedOutputUnitName; - IsDecimalEnabled = true; - - m_IsFirstTime = true; - m_model->Initialize(); - PopulateData(); -} - -void UnitConverterViewModel::ResetView() -{ - m_model->SendCommand(UCM::Command::Reset); - m_IsFirstTime = true; - OnCategoryChanged(nullptr); -} - -void UnitConverterViewModel::PopulateData() -{ - InitializeView(); -} - -void UnitConverterViewModel::OnCategoryChanged(Object ^ parameter) -{ - m_model->SendCommand(UCM::Command::Clear); - ResetCategory(); -} - -void UnitConverterViewModel::ResetCategory() -{ - UCM::Category currentCategory = CurrentCategory->GetModelCategory(); - IsCurrencyCurrentCategory = currentCategory.id == NavCategory::Serialize(ViewMode::Currency); - - m_isInputBlocked = false; - SetSelectedUnits(); - - IsCurrencyLoadingVisible = m_IsCurrencyCurrentCategory && !m_isCurrencyDataLoaded; - IsDropDownEnabled = m_Units->GetAt(0) != EMPTY_UNIT; - - UnitChanged->Execute(nullptr); -} - -void UnitConverterViewModel::SetSelectedUnits() -{ - UCM::CategorySelectionInitializer categoryInitializer = m_model->SetCurrentCategory(CurrentCategory->GetModelCategory()); - BuildUnitList(get(categoryInitializer)); - - UnitFrom = FindUnitInList(get(categoryInitializer)); - UnitTo = FindUnitInList(get(categoryInitializer)); -} - -void UnitConverterViewModel::BuildUnitList(const vector& modelUnitList) -{ - m_Units->Clear(); - for (const UCM::Unit& modelUnit : modelUnitList) - { - if (!modelUnit.isWhimsical) - { - m_Units->Append(ref new Unit(modelUnit)); - } - } - - if (m_Units->Size == 0) - { - m_Units->Append(EMPTY_UNIT); - } -} - -Unit ^ UnitConverterViewModel::FindUnitInList(UCM::Unit target) -{ - for (Unit ^ vmUnit : m_Units) - { - UCM::Unit modelUnit = vmUnit->GetModelUnit(); - if (modelUnit.id == target.id) - { - return vmUnit; - } - } - - return EMPTY_UNIT; -} - -void UnitConverterViewModel::OnUnitChanged(Object ^ parameter) -{ - if ((m_Unit1 == nullptr) || (m_Unit2 == nullptr)) - { - // Return if both Unit1 & Unit2 are not set - return; - } - - m_model->SetCurrentUnitTypes(UnitFrom->GetModelUnit(), UnitTo->GetModelUnit()); - if (m_supplementaryResultsTimer != nullptr) - { - // End timer to show results immediately - m_supplementaryResultsTimer->Cancel(); - } - if (!m_IsFirstTime) - { - SaveUserPreferences(); - } - else - { - RestoreUserPreferences(); - m_IsFirstTime = false; - } -} - -void UnitConverterViewModel::OnSwitchActive(Platform::Object ^ unused) -{ - // this can be false if this switch occurs without the user having explicitly updated any strings - // (for example, during deserialization). We only want to try this cleanup if there's actually - // something to clean up. - if (m_relocalizeStringOnSwitch) - { - // clean up any ill-formed strings that were in progress before the switch - ValueFrom = ConvertToLocalizedString(m_valueFromUnlocalized, false); - } - - SwitchConversionParameters(); - // Now deactivate the other - if (m_value1cp == ConversionParameter::Source) - { - Value2Active = false; - } - else - { - Value1Active = false; - } - - m_valueFromUnlocalized.swap(m_valueToUnlocalized); - Utils::Swap(&m_localizedValueFromFormat, &m_localizedValueToFormat); - - Utils::Swap(&m_Unit1AutomationName, &m_Unit2AutomationName); - RaisePropertyChanged(Unit1AutomationNamePropertyName); - RaisePropertyChanged(Unit2AutomationNamePropertyName); - - m_isInputBlocked = false; - m_model->SwitchActive(m_valueFromUnlocalized); -} - -String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings) -{ - Platform::String ^ result; - - if (stringToLocalize.empty()) - { - return result; - } - - m_decimalFormatter->IsDecimalPointAlwaysDisplayed = false; - m_decimalFormatter->FractionDigits = 0; - m_currencyFormatter->IsDecimalPointAlwaysDisplayed = false; - m_currencyFormatter->FractionDigits = 0; - - wstring::size_type posOfE = stringToLocalize.find(L'e'); - if (posOfE != wstring::npos) - { - wstring::size_type posOfSign = posOfE + 1; - wchar_t signOfE = stringToLocalize.at(posOfSign); - std::wstring significandStr(stringToLocalize.substr(0, posOfE)); - std::wstring exponentStr(stringToLocalize.substr(posOfSign + 1, stringToLocalize.length() - posOfSign)); - - result += ConvertToLocalizedString(significandStr, allowPartialStrings) + "e" + signOfE + ConvertToLocalizedString(exponentStr, allowPartialStrings); - } - else - { - // stringToLocalize is in en-US and has the default decimal separator, so this is safe to do. - wstring::size_type posOfDecimal = stringToLocalize.find(L'.'); - - bool hasDecimal = wstring::npos != posOfDecimal; - - if (hasDecimal) - { - if (allowPartialStrings) - { - // allow "in progress" strings, like "3." that occur during the composition of - // a final number. Without this, when typing the three characters in "3.2" - // you don't see the decimal point when typing it, you only see it once you've finally - // typed a post-decimal digit. - - m_decimalFormatter->IsDecimalPointAlwaysDisplayed = true; - m_currencyFormatter->IsDecimalPointAlwaysDisplayed = true; - } - - // force post-decimal digits so that trailing zeroes entered by the user aren't suddenly cut off. - m_decimalFormatter->FractionDigits = static_cast(stringToLocalize.length() - (posOfDecimal + 1)); - m_currencyFormatter->FractionDigits = m_currencyMaxFractionDigits; - } - - if (IsCurrencyCurrentCategory) - { - wstring currencyResult = m_currencyFormatter->Format(stod(stringToLocalize))->Data(); - wstring currencyCode = m_currencyFormatter->Currency->Data(); - - // CurrencyFormatter always includes LangCode or Symbol. Make it include LangCode - // because this includes a non-breaking space. Remove the LangCode. - auto pos = currencyResult.find(currencyCode); - if (pos != wstring::npos) - { - currencyResult.erase(pos, currencyCode.length()); - std::wsmatch sm; - if (regex_search(currencyResult, sm, regexTrimSpacesStart)) - { - currencyResult.erase(sm.prefix().length(), sm.length()); - } - - if (regex_search(currencyResult, sm, regexTrimSpacesEnd)) - { - currencyResult.erase(sm.prefix().length(), sm.length()); - } - } - - result = ref new String(currencyResult.c_str()); - } - else - { - // Convert the input string to double using stod - // Then use the decimalFormatter to reformat the double to Platform String - result = m_decimalFormatter->Format(stod(stringToLocalize)); - } - - if (hasDecimal) - { - // Since the output from GetLocaleInfoEx() and DecimalFormatter are differing for decimal string - // we are adding the below work-around of editing the string returned by DecimalFormatter - // and replacing the decimal separator with the one returned by GetLocaleInfoEx() - String ^ formattedSampleString = m_decimalFormatter->Format(stod("1.1")); - wstring formattedSampleWString = wstring(formattedSampleString->Data()); - - wstring resultWithDecimal = wstring(result->Data()); - size_t pos = resultWithDecimal.find(formattedSampleWString[1], 0); - if (pos != wstring::npos) - { - resultWithDecimal.replace(pos, 1, &m_decimalSeparator); - } - - // Copy back the edited string to the result - result = ref new String(resultWithDecimal.c_str()); - } - } - - wstring resultHolder = wstring(result->Data()); - if ((stringToLocalize.front() == L'-' && stod(stringToLocalize) == 0) || resultHolder.back() == L'-') - { - if (resultHolder.back() == L'-') - { - result = ref new String(resultHolder.erase(resultHolder.size() - 1, 1).c_str()); - } - result = L"-" + result; - } - result = Utils::LRE + result + Utils::PDF; - return result; -} - -void UnitConverterViewModel::DisplayPasteError() -{ - String ^ errorMsg = AppResourceProvider::GetInstance().GetCEngineString(StringReference(SIDS_DOMAIN)); /*SIDS_DOMAIN is for "invalid input"*/ - Value1 = errorMsg; - Value2 = errorMsg; - m_relocalizeStringOnSwitch = false; -} - -void UnitConverterViewModel::UpdateDisplay(const wstring& from, const wstring& to) -{ - String ^ fromStr = this->ConvertToLocalizedString(from, true); - UpdateInputBlocked(from); - String ^ toStr = this->ConvertToLocalizedString(to, true); - - bool updatedValueFrom = ValueFrom != fromStr; - bool updatedValueTo = ValueTo != toStr; - if (updatedValueFrom) - { - m_valueFromUnlocalized = from; - // once we've updated the unlocalized from string, we'll potentially need to clean it back up when switching between fields - // to eliminate dangling decimal points. - m_relocalizeStringOnSwitch = true; - } - - if (updatedValueTo) - { - // This is supposed to use trimming logic, but that's highly dependent - // on the auto-scaling textbox control which we dont have yet. For now, - // not doing anything. It will have to be integrated once that control is - // created. - m_valueToUnlocalized = to; - } - - m_isValue1Updating = m_Value1Active ? updatedValueFrom : updatedValueTo; - m_isValue2Updating = m_Value2Active ? updatedValueFrom : updatedValueTo; - - // Setting these properties before setting the member variables above causes - // a chain of properties that can result in the wrong result being announced - // to Narrator. We need to know which values are updating before setting the - // below properties, so that we know when to announce the result. - if (updatedValueFrom) - { - ValueFrom = fromStr; - } - - if (updatedValueTo) - { - ValueTo = toStr; - } -} - -void UnitConverterViewModel::UpdateSupplementaryResults(const std::vector>& suggestedValues) -{ - m_cacheMutex.lock(); - m_cachedSuggestedValues = suggestedValues; - m_cacheMutex.unlock(); - - // If we're already "ticking", reset the timer - if (m_supplementaryResultsTimer != nullptr) - { - m_resettingTimer = true; - m_supplementaryResultsTimer->Cancel(); - m_resettingTimer = false; - } - - // Schedule the timer - m_supplementaryResultsTimer = ThreadPoolTimer::CreateTimer( - ref new TimerElapsedHandler(this, &UnitConverterViewModel::SupplementaryResultsTimerTick, TIMER_CALLBACK_CONTEXT), - SUPPLEMENTARY_VALUES_INTERVAL, - ref new TimerDestroyedHandler(this, &UnitConverterViewModel::SupplementaryResultsTimerCancel, TIMER_CALLBACK_CONTEXT)); -} - -void UnitConverterViewModel::OnValueActivated(IActivatable ^ control) -{ - control->IsActive = true; -} - -void UnitConverterViewModel::OnButtonPressed(Platform::Object ^ parameter) -{ - NumbersAndOperatorsEnum numOpEnum = CalculatorButtonPressedEventArgs::GetOperationFromCommandParameter(parameter); - UCM::Command command = CommandFromButtonId(numOpEnum); - - // Don't clear the display if combo box is open and escape is pressed - if (command == UCM::Command::Clear && IsDropDownOpen) - { - return; - } - - static const vector OPERANDS = { UCM::Command::Zero, UCM::Command::One, UCM::Command::Two, UCM::Command::Three, UCM::Command::Four, - UCM::Command::Five, UCM::Command::Six, UCM::Command::Seven, UCM::Command::Eight, UCM::Command::Nine }; - - if (find(begin(OPERANDS), end(OPERANDS), command) != OPERANDS.end()) - { - if (m_isInputBlocked) - { - return; - } - - if (m_IsCurrencyCurrentCategory) - { - StartConversionResultTimer(); - } - } - - m_model->SendCommand(command); -} - -void UnitConverterViewModel::OnCopyCommand(Platform::Object ^ parameter) -{ - // EventWriteClipboardCopy_Start(); - CopyPasteManager::CopyToClipboard(ref new Platform::String(m_valueFromUnlocalized.c_str())); - // EventWriteClipboardCopy_Stop(); -} - -void UnitConverterViewModel::OnPasteCommand(Platform::Object ^ parameter) -{ - // if there's nothing to copy early out - if (!CopyPasteManager::HasStringToPaste()) - { - return; - } - - // Ensure that the paste happens on the UI thread - // EventWriteClipboardPaste_Start(); - // Any converter ViewMode is fine here. - CopyPasteManager::GetStringToPaste(m_Mode, NavCategory::GetGroupType(m_Mode)) - .then([this](String ^ pastedString) { OnPaste(pastedString, m_Mode); }, concurrency::task_continuation_context::use_current()); -} - -void UnitConverterViewModel::InitializeView() -{ - vector categories = m_model->GetCategories(); - for (UINT i = 0; i < categories.size(); i++) - { - Category ^ category = ref new Category(categories[i]); - m_Categories->Append(category); - } - - RestoreUserPreferences(); - CurrentCategory = ref new Category(m_model->GetCurrentCategory()); -} - -void UnitConverterViewModel::OnPropertyChanged(Platform::String ^ prop) -{ - static bool isCategoryChanging = false; - - if (prop == CurrentCategoryPropertyName) - { - isCategoryChanging = true; - CategoryChanged->Execute(nullptr); - isCategoryChanging = false; - } - else if (prop == Unit1PropertyName || prop == Unit2PropertyName) - { - // Category changes will handle updating units after they've both been updated. - // This event should only be used to update units from explicit user interaction. - if (!isCategoryChanging) - { - UnitChanged->Execute(nullptr); - } - // Get the localized automation name for each CalculationResults field - if (prop == Unit1PropertyName) - { - UpdateValue1AutomationName(); - } - else - { - UpdateValue2AutomationName(); - } - } - else if (prop == Value1PropertyName) - { - UpdateValue1AutomationName(); - } - else if (prop == Value2PropertyName) - { - UpdateValue2AutomationName(); - } - else if (prop == Value1ActivePropertyName || prop == Value2ActivePropertyName) - { - // if one of the values is activated, and as a result both are true, it means - // that we're trying to switch. - if (Value1Active && Value2Active) - { - SwitchActive->Execute(nullptr); - } - - UpdateValue1AutomationName(); - UpdateValue2AutomationName(); - } - else if (prop == SupplementaryResultsPropertyName) - { - RaisePropertyChanged(SupplementaryVisibilityPropertyName); - } - else if (prop == Value1AutomationNamePropertyName) - { - m_isValue1Updating = false; - if (!m_isValue2Updating) - { - AnnounceConversionResult(); - } - } - else if (prop == Value2AutomationNamePropertyName) - { - m_isValue2Updating = false; - if (!m_isValue1Updating) - { - AnnounceConversionResult(); - } - } - else if (prop == CurrencySymbol1PropertyName || prop == CurrencySymbol2PropertyName) - { - RaisePropertyChanged(CurrencySymbolVisibilityPropertyName); - } -} - -String ^ UnitConverterViewModel::Serialize() -{ - wstringstream out(wstringstream::out); - const wchar_t* delimiter = L"[;;;]"; - out << std::to_wstring(m_resettingTimer) << delimiter; - out << std::to_wstring(static_cast(m_value1cp)) << delimiter; - out << m_Value1Active << delimiter << m_Value2Active << delimiter; - out << m_Value1->Data() << delimiter << m_Value2->Data() << delimiter; - out << m_valueFromUnlocalized << delimiter << m_valueToUnlocalized << delimiter << L"[###]"; - wstring unitConverterSerializedData = m_model->Serialize(); - - if (!unitConverterSerializedData.empty()) - { - out << m_model->Serialize() << L"[###]"; - String ^ serializedData = ref new String(wstring(out.str()).c_str()); - return serializedData; - } - - return nullptr; -} - -void UnitConverterViewModel::Deserialize(Platform::String ^ state) -{ - wstring serializedData = wstring(state->Data()); - vector tokens = UCM::UnitConverter::StringToVector(serializedData, L"[###]"); - assert(tokens.size() >= 2); - vector viewModelData = UCM::UnitConverter::StringToVector(tokens[0], L"[;;;]"); - assert(viewModelData.size() == EXPECTEDVIEWMODELDATATOKENS); - m_resettingTimer = (viewModelData[0].compare(L"1") == 0); - m_value1cp = (ConversionParameter)_wtoi(viewModelData[1].c_str()); - m_Value1Active = (viewModelData[2].compare(L"1") == 0); - m_Value2Active = (viewModelData[3].compare(L"1") == 0); - m_Value1 = ref new String(viewModelData[4].c_str()); - m_Value2 = ref new String(viewModelData[5].c_str()); - m_valueFromUnlocalized = viewModelData[6]; - m_valueToUnlocalized = viewModelData[7]; - wstringstream modelData(wstringstream::out); - for (unsigned int i = 1; i < tokens.size(); i++) - { - modelData << tokens[i] << L"[###]"; - } - m_model->DeSerialize(modelData.str()); - InitializeView(); - RaisePropertyChanged(nullptr); // Update since all props have been updated. -} - -// Saving User Preferences of Category and Associated-Units across Sessions. -void UnitConverterViewModel::SaveUserPreferences() -{ - if (UnitsAreValid()) - { - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - if (!m_IsCurrencyCurrentCategory) - { - auto userPreferences = m_model->SaveUserPreferences(); - localSettings->Values->Insert(ref new String(L"UnitConverterPreferences"), ref new String(userPreferences.c_str())); - } - else - { - // Currency preferences shouldn't be saved in the same way as standard converter modes because - // the delay loading creates a big mess of issues that are better to avoid. - localSettings->Values->Insert(UnitConverterResourceKeys::CurrencyUnitFromKey, UnitFrom->Abbreviation); - localSettings->Values->Insert(UnitConverterResourceKeys::CurrencyUnitToKey, UnitTo->Abbreviation); - } - } -} - -// Restoring User Preferences of Category and Associated-Units. -void UnitConverterViewModel::RestoreUserPreferences() -{ - if (!IsCurrencyCurrentCategory) - { - ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings; - if (localSettings->Values->HasKey(ref new String(L"UnitConverterPreferences"))) - { - String ^ userPreferences = safe_cast(localSettings->Values->Lookup(ref new String(L"UnitConverterPreferences"))); - m_model->RestoreUserPreferences(userPreferences->Data()); - } - } -} - -void UnitConverterViewModel::OnCurrencyDataLoadFinished(bool didLoad) -{ - m_isCurrencyDataLoaded = true; - CurrencyDataLoadFailed = !didLoad; - m_model->ResetCategoriesAndRatios(); - m_model->Calculate(); - ResetCategory(); - - StringReference key = didLoad ? UnitConverterResourceKeys::CurrencyRatesUpdated : UnitConverterResourceKeys::CurrencyRatesUpdateFailed; - String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(key); - Announcement = CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(announcement); -} - -void UnitConverterViewModel::OnCurrencyTimestampUpdated(_In_ const wstring& timestamp, bool isWeekOld) -{ - CurrencyDataIsWeekOld = isWeekOld; - CurrencyTimestamp = ref new String(timestamp.c_str()); -} - -void UnitConverterViewModel::RefreshCurrencyRatios() -{ - m_isCurrencyDataLoaded = false; - IsCurrencyLoadingVisible = true; - - String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(UnitConverterResourceKeys::UpdatingCurrencyRates); - Announcement = CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(announcement); - - auto refreshTask = create_task(m_model->RefreshCurrencyRatios()); - refreshTask.then( - [this](const pair& refreshResult) { - bool didLoad = refreshResult.first; - wstring timestamp = refreshResult.second; - - OnCurrencyTimestampUpdated(timestamp, false /*isWeekOldData*/); - OnCurrencyDataLoadFinished(didLoad); - }, - task_continuation_context::use_current()); -} - -void UnitConverterViewModel::OnNetworkBehaviorChanged(_In_ NetworkAccessBehavior newBehavior) -{ - CurrencyDataLoadFailed = false; - NetworkBehavior = newBehavior; -} - -UnitConversionManager::Command UnitConverterViewModel::CommandFromButtonId(NumbersAndOperatorsEnum button) -{ - UCM::Command command; - - switch (button) - { - case NumbersAndOperatorsEnum::Zero: - command = UCM::Command::Zero; - break; - case NumbersAndOperatorsEnum::One: - command = UCM::Command::One; - break; - case NumbersAndOperatorsEnum::Two: - command = UCM::Command::Two; - break; - case NumbersAndOperatorsEnum::Three: - command = UCM::Command::Three; - break; - case NumbersAndOperatorsEnum::Four: - command = UCM::Command::Four; - break; - case NumbersAndOperatorsEnum::Five: - command = UCM::Command::Five; - break; - case NumbersAndOperatorsEnum::Six: - command = UCM::Command::Six; - break; - case NumbersAndOperatorsEnum::Seven: - command = UCM::Command::Seven; - break; - case NumbersAndOperatorsEnum::Eight: - command = UCM::Command::Eight; - break; - case NumbersAndOperatorsEnum::Nine: - command = UCM::Command::Nine; - break; - case NumbersAndOperatorsEnum::Decimal: - command = UCM::Command::Decimal; - break; - case NumbersAndOperatorsEnum::Negate: - command = UCM::Command::Negate; - break; - case NumbersAndOperatorsEnum::Backspace: - command = UCM::Command::Backspace; - break; - case NumbersAndOperatorsEnum::Clear: - command = UCM::Command::Clear; - break; - default: - command = UCM::Command::None; - break; - } - - return command; -} - -void UnitConverterViewModel::SupplementaryResultsTimerTick(ThreadPoolTimer ^ timer) -{ - timer->Cancel(); -} - -void UnitConverterViewModel::SupplementaryResultsTimerCancel(ThreadPoolTimer ^ timer) -{ - if (!m_resettingTimer) - { - RefreshSupplementaryResults(); - } -} - -void UnitConverterViewModel::RefreshSupplementaryResults() -{ - m_cacheMutex.lock(); - m_SupplementaryResults->Clear(); - - vector whimsicals; - - for (tuple suggestedValue : m_cachedSuggestedValues) - { - SupplementaryResult ^ result = - ref new SupplementaryResult(this->ConvertToLocalizedString(get<0>(suggestedValue), false), ref new Unit(get<1>(suggestedValue))); - if (result->IsWhimsical()) - { - whimsicals.push_back(result); - } - else - { - m_SupplementaryResults->Append(result); - } - } - - if (whimsicals.size() > 0) - { - m_SupplementaryResults->Append(whimsicals[0]); - } - - m_cacheMutex.unlock(); - RaisePropertyChanged(SupplementaryResultsPropertyName); - // EventWriteConverterSupplementaryResultsUpdated(); -} - -// When UpdateDisplay is called, the ViewModel will remember the From/To unlocalized display values -// This function will announce the conversion result after the ValueTo/ValueFrom automation names update, -// only if the new unlocalized display values are different from the last announced values, and if the -// values are not both zero. -void UnitConverterViewModel::AnnounceConversionResult() -{ - if ((m_valueFromUnlocalized != m_lastAnnouncedFrom || m_valueToUnlocalized != m_lastAnnouncedTo) && Unit1 != nullptr && Unit2 != nullptr) - { - m_lastAnnouncedFrom = m_valueFromUnlocalized; - m_lastAnnouncedTo = m_valueToUnlocalized; - - Unit ^ unitFrom = Value1Active ? Unit1 : Unit2; - Unit ^ unitTo = (unitFrom == Unit1) ? Unit2 : Unit1; - m_lastAnnouncedConversionResult = GetLocalizedConversionResultStringFormat(ValueFrom, unitFrom->Name, ValueTo, unitTo->Name); - - Announcement = CalculatorAnnouncement::GetDisplayUpdatedAnnouncement(m_lastAnnouncedConversionResult); - } -} - -void UnitConverterViewModel::UpdateInputBlocked(_In_ const wstring& currencyInput) -{ - // currencyInput is in en-US and has the default decimal separator, so this is safe to do. - auto posOfDecimal = currencyInput.find(L'.'); - m_isInputBlocked = false; - if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory) - { - m_isInputBlocked = (posOfDecimal + static_cast(m_currencyMaxFractionDigits) + 1 == currencyInput.length()); - } -} - -NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate) -{ - static_assert(NumbersAndOperatorsEnum::Zero < NumbersAndOperatorsEnum::One, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::One < NumbersAndOperatorsEnum::Two, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Two < NumbersAndOperatorsEnum::Three, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Three < NumbersAndOperatorsEnum::Four, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Four < NumbersAndOperatorsEnum::Five, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Five < NumbersAndOperatorsEnum::Six, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Six < NumbersAndOperatorsEnum::Seven, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Seven < NumbersAndOperatorsEnum::Eight, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Eight < NumbersAndOperatorsEnum::Nine, "NumbersAndOperatorsEnum order is invalid"); - static_assert(NumbersAndOperatorsEnum::Zero < NumbersAndOperatorsEnum::Nine, "NumbersAndOperatorsEnum order is invalid"); - - NumbersAndOperatorsEnum mappedValue = NumbersAndOperatorsEnum::None; - canSendNegate = false; - - switch (ch) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - mappedValue = NumbersAndOperatorsEnum::Zero + static_cast(ch - L'0'); - canSendNegate = true; - break; - - case '-': - mappedValue = NumbersAndOperatorsEnum::Negate; - break; - - default: - // Respect the user setting for decimal separator - if (ch == m_decimalSeparator) - { - mappedValue = NumbersAndOperatorsEnum::Decimal; - canSendNegate = true; - break; - } - } - - if (mappedValue == NumbersAndOperatorsEnum::None) - { - if (LocalizationSettings::GetInstance().IsLocalizedDigit(ch)) - { - mappedValue = NumbersAndOperatorsEnum::Zero - + static_cast(ch - LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'0')); - canSendNegate = true; - } - } - - return mappedValue; -} - -void UnitConverterViewModel::OnPaste(String ^ stringToPaste, ViewMode mode) -{ - // If pastedString is invalid("NoOp") then display pasteError else process the string - if (stringToPaste == StringReference(CopyPasteManager::PasteErrorString)) - { - this->DisplayPasteError(); - return; - } - - TraceLogger::GetInstance().LogValidInputPasted(mode); - bool isFirstLegalChar = true; - bool sendNegate = false; - wstring accumulation = L""; - - for (auto it = stringToPaste->Begin(); it != stringToPaste->End(); it++) - { - bool canSendNegate = false; - - NumbersAndOperatorsEnum op = MapCharacterToButtonId(*it, canSendNegate); - - if (NumbersAndOperatorsEnum::None != op) - { - if (isFirstLegalChar) - { - // Send Clear before sending something that will actually apply - // to the field. - m_model->SendCommand(UCM::Command::Clear); - isFirstLegalChar = false; - - // If the very first legal character is a - sign, send negate - // after sending the next legal character. Send nothing now, or - // it will be ignored. - if (NumbersAndOperatorsEnum::Negate == op) - { - sendNegate = true; - } - } - - // Negate is only allowed if it's the first legal character, which is handled above. - if (NumbersAndOperatorsEnum::Negate != op) - { - UCM::Command cmd = CommandFromButtonId(op); - m_model->SendCommand(cmd); - - if (sendNegate) - { - if (canSendNegate) - { - m_model->SendCommand(UCM::Command::Negate); - } - sendNegate = false; - } - } - - accumulation += *it; - UpdateInputBlocked(accumulation); - if (m_isInputBlocked) - { - break; - } - } - else - { - sendNegate = false; - } - } -} - -String ^ UnitConverterViewModel::GetLocalizedAutomationName(_In_ String ^ displayvalue, _In_ String ^ unitname, _In_ String ^ format) -{ - String ^ valueToLocalize = displayvalue; - if (displayvalue == ValueFrom && Utils::IsLastCharacterTarget(m_valueFromUnlocalized, m_decimalSeparator)) - { - // Need to compute a second localized value for the automation - // name that does not include the decimal separator. - displayvalue = ConvertToLocalizedString(m_valueFromUnlocalized, false /*allowTrailingDecimal*/); - format = m_localizedValueFromDecimalFormat; - } - - wstring localizedResult = LocalizationStringUtil::GetLocalizedString(format->Data(), displayvalue->Data(), unitname->Data()); - return ref new String(localizedResult.c_str()); -} - -String - ^ UnitConverterViewModel::GetLocalizedConversionResultStringFormat( - _In_ String ^ fromValue, - _In_ String ^ fromUnit, - _In_ String ^ toValue, - _In_ String ^ toUnit) -{ - String ^ localizedString = - ref new String(LocalizationStringUtil::GetLocalizedString( - m_localizedConversionResultFormat->Data(), fromValue->Data(), fromUnit->Data(), toValue->Data(), toUnit->Data()) - .c_str()); - return localizedString; -} - -void UnitConverterViewModel::UpdateValue1AutomationName() -{ - if (Unit1) - { - Value1AutomationName = GetLocalizedAutomationName(Value1, Unit1->AccessibleName, m_localizedValueFromFormat); - } -} - -void UnitConverterViewModel::UpdateValue2AutomationName() -{ - if (Unit2) - { - Value2AutomationName = GetLocalizedAutomationName(Value2, Unit2->AccessibleName, m_localizedValueToFormat); - } -} - -void UnitConverterViewModel::OnMaxDigitsReached() -{ - String ^ format = AppResourceProvider::GetInstance().GetResourceString(UnitConverterResourceKeys::MaxDigitsReachedFormat); - const wstring& announcement = LocalizationStringUtil::GetLocalizedString(format->Data(), m_lastAnnouncedConversionResult->Data()); - Announcement = CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(StringReference(announcement.c_str())); -} - -bool UnitConverterViewModel::UnitsAreValid() -{ - return UnitFrom != nullptr && !UnitFrom->Abbreviation->IsEmpty() && UnitTo != nullptr && !UnitTo->Abbreviation->IsEmpty(); -} - -void UnitConverterViewModel::StartConversionResultTimer() -{ - m_conversionResultTaskHelper = make_unique(CONVERSION_FINALIZED_DELAY_IN_MS, [this]() { - if (UnitsAreValid()) - { - String ^ valueFrom = m_Value1Active ? m_Value1 : m_Value2; - String ^ valueTo = m_Value1Active ? m_Value2 : m_Value1; - TraceLogger::GetInstance().LogConversionResult(valueFrom->Data(), UnitFrom->ToString()->Data(), valueTo->Data(), UnitTo->ToString()->Data()); - } - }); -} - -String ^ SupplementaryResult::GetLocalizedAutomationName() -{ - auto format = AppResourceProvider::GetInstance().GetResourceString("SupplementaryUnit_AutomationName"); - return ref new String(LocalizationStringUtil::GetLocalizedString(format->Data(), this->Value->Data(), this->Unit->Name->Data()).c_str()); -} diff --git a/src/CalcViewModel/UnitConverterViewModel.h b/src/CalcViewModel/UnitConverterViewModel.h deleted file mode 100644 index 1fb67ee8..00000000 --- a/src/CalcViewModel/UnitConverterViewModel.h +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "CalcManager/UnitConverter.h" -#include "Common/Utils.h" -#include "Common/NetworkManager.h" -#include "Common/Automation/NarratorAnnouncement.h" -#include "Common/ConversionResultTaskHelper.h" -#include "Common/CalculatorButtonUser.h" -#include "Common/NavCategory.h" - -namespace CalculatorApp -{ - namespace ViewModel - { - [Windows::UI::Xaml::Data::Bindable] public ref class Category sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - internal : Category(const UnitConversionManager::Category& category) - : m_original(category) - { - } - - public: - OBSERVABLE_OBJECT(); - - property Platform::String - ^ Name { Platform::String ^ get() { return ref new Platform::String(m_original.name.c_str()); } } - - property Windows::UI::Xaml::Visibility NegateVisibility - { - Windows::UI::Xaml::Visibility get() - { - return m_original.supportsNegative ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed; - } - } - - internal : const UnitConversionManager::Category& GetModelCategory() const - { - return m_original; - } - - private: - const UnitConversionManager::Category m_original; - }; - - [Windows::UI::Xaml::Data::Bindable] public ref class Unit sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - internal : Unit(const UnitConversionManager::Unit& unit) - : m_original(unit) - { - } - - public: - OBSERVABLE_OBJECT(); - - property Platform::String - ^ Name { Platform::String ^ get() { return ref new Platform::String(m_original.name.c_str()); } } - - property Platform::String - ^ AccessibleName { Platform::String ^ get() { return ref new Platform::String(m_original.accessibleName.c_str()); } } - - property Platform::String - ^ Abbreviation { Platform::String ^ get() { return ref new Platform::String(m_original.abbreviation.c_str()); } } - - // This method is used to return the desired automation name for default unit in UnitConverter combo box. - Platform::String - ^ ToString() override - { - return AccessibleName; - } - - internal : const UnitConversionManager::Unit& GetModelUnit() const - { - return m_original; - } - - private: - const UnitConversionManager::Unit m_original; - }; - - [Windows::UI::Xaml::Data::Bindable] public ref class SupplementaryResult sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - internal : SupplementaryResult(Platform::String ^ value, Unit ^ unit) - : m_Value(value) - , m_Unit(unit) - { - } - - bool IsWhimsical() const - { - return m_Unit->GetModelUnit().isWhimsical; - } - - Platform::String ^ GetLocalizedAutomationName(); - - public: - OBSERVABLE_OBJECT(); - - OBSERVABLE_PROPERTY_R(Platform::String ^, Value); - OBSERVABLE_PROPERTY_R(CalculatorApp::ViewModel::Unit ^, Unit); - }; - - interface class IActivatable - { - virtual property bool IsActive; - }; - - template - ref class Activatable sealed : public IActivatable - { - private: - TActivatable m_activatable; - - public: - Activatable(TActivatable activatable) - : m_activatable(activatable) - { - } - - virtual property bool IsActive - { - bool get() - { - return m_activatable->IsActive; - } - void set(bool value) - { - m_activatable->IsActive = value; - } - } - }; - - template - IActivatable - ^ AsActivatable(TActivatable activatable) { return ref new Activatable(activatable); } - - [Windows::UI::Xaml::Data::Bindable] public ref class UnitConverterViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged - { - internal : UnitConverterViewModel(const std::shared_ptr& model); - - public: - OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); - - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Categories); - OBSERVABLE_PROPERTY_RW(Category ^, CurrentCategory); - OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, Mode); - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Units); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencySymbol1); - OBSERVABLE_PROPERTY_RW(Unit ^, Unit1); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Value1); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencySymbol2); - OBSERVABLE_PROPERTY_RW(Unit ^, Unit2); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Value2); - OBSERVABLE_NAMED_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, SupplementaryResults); - OBSERVABLE_PROPERTY_RW(bool, Value1Active); - OBSERVABLE_PROPERTY_RW(bool, Value2Active); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Value1AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Value2AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Unit1AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, Unit2AutomationName); - OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement ^, Announcement); - OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsDropDownOpen); - OBSERVABLE_PROPERTY_RW(bool, IsDropDownEnabled); - OBSERVABLE_NAMED_PROPERTY_RW(bool, IsCurrencyLoadingVisible); - OBSERVABLE_PROPERTY_RW(bool, IsCurrencyCurrentCategory); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencyRatioEquality); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencyRatioEqualityAutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencyTimestamp); - OBSERVABLE_NAMED_PROPERTY_RW(CalculatorApp::NetworkAccessBehavior, NetworkBehavior); - OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataLoadFailed); - OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataIsWeekOld); - - property Windows::UI::Xaml::Visibility SupplementaryVisibility - { - Windows::UI::Xaml::Visibility get() - { - return SupplementaryResults->Size > 0 ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed; - } - } - - property Windows::UI::Xaml::Visibility CurrencySymbolVisibility - { - Windows::UI::Xaml::Visibility get() - { - return (CurrencySymbol1->IsEmpty() || CurrencySymbol2->IsEmpty()) ? Windows::UI::Xaml::Visibility::Collapsed - : Windows::UI::Xaml::Visibility::Visible; - } - } - - COMMAND_FOR_METHOD(CategoryChanged, UnitConverterViewModel::OnCategoryChanged); - COMMAND_FOR_METHOD(UnitChanged, UnitConverterViewModel::OnUnitChanged); - COMMAND_FOR_METHOD(SwitchActive, UnitConverterViewModel::OnSwitchActive); - COMMAND_FOR_METHOD(ButtonPressed, UnitConverterViewModel::OnButtonPressed); - COMMAND_FOR_METHOD(CopyCommand, UnitConverterViewModel::OnCopyCommand); - COMMAND_FOR_METHOD(PasteCommand, UnitConverterViewModel::OnPasteCommand); - - void AnnounceConversionResult(); - - internal : void ResetView(); - void PopulateData(); - NumbersAndOperatorsEnum MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate); - void DisplayPasteError(); - void OnValueActivated(IActivatable ^ control); - void OnPaste(Platform::String ^ stringToPaste, CalculatorApp::Common::ViewMode mode); - - void OnCopyCommand(Platform::Object ^ parameter); - void OnPasteCommand(Platform::Object ^ parameter); - - Platform::String - ^ GetLocalizedAutomationName(_In_ Platform::String ^ displayvalue, _In_ Platform::String ^ unitname, _In_ Platform::String ^ format); - Platform::String - ^ GetLocalizedConversionResultStringFormat( - _In_ Platform::String ^ fromValue, - _In_ Platform::String ^ fromUnit, - _In_ Platform::String ^ toValue, - _In_ Platform::String ^ toUnit); - void UpdateValue1AutomationName(); - void UpdateValue2AutomationName(); - Platform::String ^ Serialize(); - void Deserialize(Platform::String ^ state); - void ResetCategoriesAndRatio(); - - // Saving And Restoring User Preferences of Category and Associated-Units across Sessions. - void SaveUserPreferences(); - void RestoreUserPreferences(); - - void OnCurrencyDataLoadFinished(bool didLoad); - void OnCurrencyTimestampUpdated(_In_ const std::wstring& timestamp, bool isWeekOld); - void RefreshCurrencyRatios(); - void OnNetworkBehaviorChanged(_In_ CalculatorApp::NetworkAccessBehavior newBehavior); - - const std::wstring& GetValueFromUnlocalized() const - { - return m_valueFromUnlocalized; - } - const std::wstring& GetValueToUnlocalized() const - { - return m_valueToUnlocalized; - } - - // used by UnitConverterVMCallback - void UpdateDisplay(const std::wstring& from, const std::wstring& to); - void UpdateSupplementaryResults(const std::vector>& suggestedValues); - void OnMaxDigitsReached(); - - void BuildUnitList(const std::vector& modelUnitList); - Unit ^ FindUnitInList(UnitConversionManager::Unit target); - void SetSelectedUnits(); - - private: - void InitializeView(); - void OnPropertyChanged(Platform::String ^ prop); - void OnCategoryChanged(Platform::Object ^ unused); - void OnUnitChanged(Platform::Object ^ unused); - void OnSwitchActive(Platform::Object ^ unused); - UnitConversionManager::Command CommandFromButtonId(CalculatorApp::NumbersAndOperatorsEnum button); - void SupplementaryResultsTimerTick(Windows::System::Threading::ThreadPoolTimer ^ timer); - void SupplementaryResultsTimerCancel(Windows::System::Threading::ThreadPoolTimer ^ timer); - void RefreshSupplementaryResults(); - void UpdateInputBlocked(_In_ const std::wstring& currencyInput); - bool UnitsAreValid(); - void ResetCategory(); - - void OnButtonPressed(Platform::Object ^ parameter); - Platform::String ^ ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings); - - void StartConversionResultTimer(); - - std::shared_ptr m_model; - wchar_t m_decimalSeparator; - - enum class ConversionParameter - { - Source, - Target - } m_value1cp; - property Platform::String^ ValueFrom - { - Platform::String^ get() { return m_value1cp == ConversionParameter::Source ? Value1 : Value2; } - void set(Platform::String^ value) { m_value1cp == ConversionParameter::Source ? Value1 = value : Value2 = value; } - } - property Unit^ UnitFrom - { - Unit^ get() { return m_value1cp == ConversionParameter::Source ? Unit1 : Unit2; } - void set(Unit^ value) { m_value1cp == ConversionParameter::Source ? Unit1 = value : Unit2 = value; } - } - property Platform::String^ ValueTo - { - Platform::String^ get() { return m_value1cp == ConversionParameter::Target ? Value1 : Value2; } - void set(Platform::String^ value) { m_value1cp == ConversionParameter::Target ? Value1 = value : Value2 = value; } - } - property Unit^ UnitTo - { - Unit^ get() { return m_value1cp == ConversionParameter::Target ? Unit1 : Unit2; } - void set(Unit^ value) { m_value1cp == ConversionParameter::Target ? Unit1 = value : Unit2 = value; } - } - void SwitchConversionParameters() - { - m_value1cp = m_value1cp == ConversionParameter::Source ? ConversionParameter::Target : ConversionParameter::Source; - } - - private: - bool m_isInputBlocked; - Windows::System::Threading::ThreadPoolTimer ^ m_supplementaryResultsTimer; - bool m_resettingTimer; - std::vector> m_cachedSuggestedValues; - std::mutex m_cacheMutex; - Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_decimalFormatter; - Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter; - int m_currencyMaxFractionDigits; - std::wstring m_valueFromUnlocalized; - std::wstring m_valueToUnlocalized; - bool m_relocalizeStringOnSwitch; - // For Saving the User Preferences only if the Unit converter ViewModel is initialised for the first time - bool m_IsFirstTime; - - Platform::String ^ m_localizedValueFromFormat; - Platform::String ^ m_localizedValueFromDecimalFormat; - Platform::String ^ m_localizedValueToFormat; - Platform::String ^ m_localizedConversionResultFormat; - Platform::String ^ m_localizedInputUnitName; - Platform::String ^ m_localizedOutputUnitName; - - bool m_isValue1Updating; - bool m_isValue2Updating; - std::wstring m_lastAnnouncedFrom; - std::wstring m_lastAnnouncedTo; - Platform::String ^ m_lastAnnouncedConversionResult; - - bool m_isCurrencyDataLoaded; - - std::unique_ptr m_conversionResultTaskHelper; - }; - - class UnitConverterVMCallback : public UnitConversionManager::IUnitConverterVMCallback - { - public: - UnitConverterVMCallback(UnitConverterViewModel ^ viewModel) - : m_viewModel(viewModel) - { - } - - void DisplayCallback(const std::wstring& from, const std::wstring& to) override - { - m_viewModel->UpdateDisplay(from, to); - } - - void SuggestedValueCallback(const std::vector>& suggestedValues) override - { - m_viewModel->UpdateSupplementaryResults(suggestedValues); - } - - void MaxDigitsReached() - { - m_viewModel->OnMaxDigitsReached(); - } - - private: - UnitConverterViewModel ^ m_viewModel; - }; - - class ViewModelCurrencyCallback : public UnitConversionManager::IViewModelCurrencyCallback - { - public: - ViewModelCurrencyCallback(UnitConverterViewModel ^ viewModel) - : m_viewModel(viewModel) - { - } - - void CurrencyDataLoadFinished(bool didLoad) override - { - m_viewModel->OnCurrencyDataLoadFinished(didLoad); - } - - void CurrencySymbolsCallback(const std::wstring& symbol1, const std::wstring& symbol2) override - { - Platform::String ^ sym1 = Platform::StringReference(symbol1.c_str()); - Platform::String ^ sym2 = Platform::StringReference(symbol2.c_str()); - - bool value1Active = m_viewModel->Value1Active; - m_viewModel->CurrencySymbol1 = value1Active ? sym1 : sym2; - m_viewModel->CurrencySymbol2 = value1Active ? sym2 : sym1; - } - - void CurrencyRatiosCallback(_In_ const std::wstring& ratioEquality, _In_ const std::wstring& accRatioEquality) override - { - m_viewModel->CurrencyRatioEquality = ref new Platform::String(ratioEquality.c_str()); - m_viewModel->CurrencyRatioEqualityAutomationName = ref new Platform::String(accRatioEquality.c_str()); - } - - void CurrencyTimestampCallback(_In_ const std::wstring& timestamp, bool isWeekOld) override - { - m_viewModel->OnCurrencyTimestampUpdated(timestamp, isWeekOld); - } - - void NetworkBehaviorChanged(_In_ int newBehavior) override - { - m_viewModel->OnNetworkBehaviorChanged(static_cast(newBehavior)); - } - - private: - UnitConverterViewModel ^ m_viewModel; - }; - } -} diff --git a/src/CalcViewModel/ViewState.cpp b/src/CalcViewModel/ViewState.cpp deleted file mode 100644 index 63a5d30e..00000000 --- a/src/CalcViewModel/ViewState.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "ViewState.h" - -namespace CalculatorApp -{ - namespace ViewState - { - Platform::StringReference Snap(L"Snap"); - Platform::StringReference DockedView(L"DockedView"); - - bool IsValidViewState(Platform::String ^ viewState) - { - return viewState->Equals(ViewState::Snap) || viewState->Equals(ViewState::DockedView); - } - } -} diff --git a/src/CalcViewModel/ViewState.h b/src/CalcViewModel/ViewState.h deleted file mode 100644 index 0a103d09..00000000 --- a/src/CalcViewModel/ViewState.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace ViewState - { - extern Platform::StringReference Snap; - extern Platform::StringReference DockedView; - - bool IsValidViewState(Platform::String ^ viewState); - } -} diff --git a/src/CalcViewModel/packages.config b/src/CalcViewModel/packages.config deleted file mode 100644 index cef4e13e..00000000 --- a/src/CalcViewModel/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/CalcViewModel/pch.cpp b/src/CalcViewModel/pch.cpp deleted file mode 100644 index 1da170eb..00000000 --- a/src/CalcViewModel/pch.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" diff --git a/src/CalcViewModel/pch.h b/src/CalcViewModel/pch.h deleted file mode 100644 index 142e05f8..00000000 --- a/src/CalcViewModel/pch.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "targetver.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -// Windows headers define min/max macros. -// Disable it for project code. -#define NOMINMAX - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// C++\WinRT Headers -#include "winrt/base.h" -#include "winrt/Windows.Foundation.Diagnostics.h" -#include "winrt/Windows.Globalization.h" -#include "winrt/Windows.Globalization.DateTimeFormatting.h" -#include "winrt/Windows.System.UserProfile.h" -#include "winrt/Windows.UI.Xaml.h" - -// The following namespaces exist as a convenience to resolve -// ambiguity for Windows types in the Windows::UI::Xaml::Automation::Peers -// namespace that only exist on RS3. -// Once the app switches to min version RS3, the namespaces can be removed. -// TODO - MSFT 12735088 -namespace StandardPeers = Windows::UI::Xaml::Automation::Peers; -namespace CalculatorApp::Common::Automation -{ -} -namespace CustomPeers = CalculatorApp::Common::Automation; diff --git a/src/CalcViewModel/targetver.h b/src/CalcViewModel/targetver.h deleted file mode 100644 index 221efabb..00000000 --- a/src/CalcViewModel/targetver.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/src/Calculator.Droid/Assets/AboutAssets.txt b/src/Calculator.Droid/Assets/AboutAssets.txt new file mode 100644 index 00000000..ee398862 --- /dev/null +++ b/src/Calculator.Droid/Assets/AboutAssets.txt @@ -0,0 +1,19 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories) and given a Build Action of "AndroidAsset". + +These files will be deployed with you package and will be accessible using Android's +AssetManager, like this: + +public class ReadAsset : Activity +{ + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + InputStream input = Assets.Open ("my_asset.txt"); + } +} + +Additionally, some Android functions will automatically load asset files: + +Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); \ No newline at end of file diff --git a/src/Calculator.Droid/Assets/Fonts/winjs-symbols.ttf b/src/Calculator.Droid/Assets/Fonts/winjs-symbols.ttf new file mode 100644 index 00000000..f502611c Binary files /dev/null and b/src/Calculator.Droid/Assets/Fonts/winjs-symbols.ttf differ diff --git a/src/Calculator.Droid/Calculator.Droid.csproj b/src/Calculator.Droid/Calculator.Droid.csproj new file mode 100644 index 00000000..b9661773 --- /dev/null +++ b/src/Calculator.Droid/Calculator.Droid.csproj @@ -0,0 +1,91 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {A8517645-FA26-4BBE-A931-52FCF16DB2C6} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Calculator.Droid + Calculator.Droid + 512 + true + Resources\Resource.Designer.cs + Off + False + v8.0 + Properties\AndroidManifest.xml + True + ..\Calculator.Shared\Strings + + + true + portable + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + True + None + + + portable + true + true + true + bin\Release\ + TRACE + prompt + 4 + False + SdkOnly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Calculator.Droid/Main.cs b/src/Calculator.Droid/Main.cs new file mode 100644 index 00000000..555b313a --- /dev/null +++ b/src/Calculator.Droid/Main.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Com.Nostra13.Universalimageloader.Core; +using Windows.UI.Xaml.Media; + +namespace WindowsCalculator.Droid +{ + [global::Android.App.ApplicationAttribute( + Label = "@string/ApplicationName", + LargeHeap = true, + HardwareAccelerated = true, + Theme = "@style/AppTheme" + )] + public class Application : Windows.UI.Xaml.NativeApplication + { + public Application(IntPtr javaReference, JniHandleOwnership transfer) + : base(new App(), javaReference, transfer) + { + ConfigureUniversalImageLoader(); + } + + private void ConfigureUniversalImageLoader() + { + // Create global configuration and initialize ImageLoader with this config + ImageLoaderConfiguration config = new ImageLoaderConfiguration + .Builder(Context) + .Build(); + + ImageLoader.Instance.Init(config); + + ImageSource.DefaultImageLoader = ImageLoader.Instance.LoadImageAsync; + } + } +} diff --git a/src/Calculator.Droid/MainActivity.cs b/src/Calculator.Droid/MainActivity.cs new file mode 100644 index 00000000..94ad503c --- /dev/null +++ b/src/Calculator.Droid/MainActivity.cs @@ -0,0 +1,18 @@ +using Android.App; +using Android.Widget; +using Android.OS; +using Android.Content.PM; +using Android.Views; + +namespace WindowsCalculator.Droid +{ + [Activity( + MainLauncher = true, + ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, + WindowSoftInputMode = SoftInput.AdjustPan | SoftInput.StateHidden + )] + public class MainActivity : Windows.UI.Xaml.ApplicationActivity + { + } +} + diff --git a/src/Calculator.Droid/Properties/AndroidManifest.xml b/src/Calculator.Droid/Properties/AndroidManifest.xml new file mode 100644 index 00000000..f789a779 --- /dev/null +++ b/src/Calculator.Droid/Properties/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/Calculator.Droid/Properties/AssemblyInfo.cs b/src/Calculator.Droid/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d1561776 --- /dev/null +++ b/src/Calculator.Droid/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Android.App; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UnoQuickStart.Droid")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UnoQuickStart.Droid")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Calculator.Droid/Resources/AboutResources.txt b/src/Calculator.Droid/Resources/AboutResources.txt new file mode 100644 index 00000000..c2bca974 --- /dev/null +++ b/src/Calculator.Droid/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/src/Calculator.Droid/Resources/drawable/Icon.png b/src/Calculator.Droid/Resources/drawable/Icon.png new file mode 100644 index 00000000..8074c4c5 Binary files /dev/null and b/src/Calculator.Droid/Resources/drawable/Icon.png differ diff --git a/src/Calculator.Droid/Resources/values/Strings.xml b/src/Calculator.Droid/Resources/values/Strings.xml new file mode 100644 index 00000000..d4c27901 --- /dev/null +++ b/src/Calculator.Droid/Resources/values/Strings.xml @@ -0,0 +1,5 @@ + + + Hello World, Click Me! + UnoQuickStart.Droid + diff --git a/src/Calculator.Droid/Resources/values/Styles.xml b/src/Calculator.Droid/Resources/values/Styles.xml new file mode 100644 index 00000000..d668a8e0 --- /dev/null +++ b/src/Calculator.Droid/Resources/values/Styles.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/src/Calculator.Shared/App.xaml b/src/Calculator.Shared/App.xaml new file mode 100644 index 00000000..b190fe53 --- /dev/null +++ b/src/Calculator.Shared/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/src/Calculator.Shared/App.xaml.cs b/src/Calculator.Shared/App.xaml.cs new file mode 100644 index 00000000..dac57e65 --- /dev/null +++ b/src/Calculator.Shared/App.xaml.cs @@ -0,0 +1,147 @@ +using CalculatorApp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.ApplicationModel.Core; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Core; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace CalculatorApp +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + static bool m_isAnimationEnabled = true; + + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + this.Suspending += OnSuspending; + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { +#if DEBUG + if (System.Diagnostics.Debugger.IsAttached) + { + // this.DebugSettings.EnableFrameRateCounter = true; + } +#endif + +#if !HAS_UNO + var userSettings = new Windows.UI.ViewManagement.UISettings(); + m_isAnimationEnabled = userSettings.AnimationsEnabled; +#endif + + Frame rootFrame = Windows.UI.Xaml.Window.Current.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + rootFrame.NavigationFailed += OnNavigationFailed; + + if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) + { + //TODO: Load state from previously suspended application + } + + // Place the frame in the current Window + Windows.UI.Xaml.Window.Current.Content = rootFrame; + } + + if (e.PrelaunchActivated == false) + { + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Navigate(typeof(MainPage), e.Arguments); + } + // Ensure the current window is active + Windows.UI.Xaml.Window.Current.Activate(); + } + } + + /// + /// Return True if animation is enabled by user setting. + /// + public static bool IsAnimationEnabled() + { + return m_isAnimationEnabled; + } + + /// + /// Return the current application view state. The value + /// will match one of the constants in the ViewState namespace. + /// + public static string GetAppViewState() + { + String newViewState; + CoreWindow window = CoreWindow.GetForCurrentThread(); + if ((window.Bounds.Width >= 560) && (window.Bounds.Height >= 356)) + { + newViewState = ViewState.DockedView; + } + else + { + newViewState = ViewState.Snap; + } + + return newViewState; + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception($"Failed to load Page {e.SourcePageType}: {e.Exception}"); + + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + //TODO: Save application state and stop any background activity + deferral.Complete(); + } + } +} diff --git a/src/Calculator/Assets/CalcMDL2.ttf b/src/Calculator.Shared/Assets/CalcMDL2.ttf similarity index 100% rename from src/Calculator/Assets/CalcMDL2.ttf rename to src/Calculator.Shared/Assets/CalcMDL2.ttf diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_scale-125.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-125.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_scale-150.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-150.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_scale-400.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_scale-400.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-16.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-16.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-16.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-16.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-20.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-20.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-20.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-20.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-24.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-24.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-24.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-24.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-256.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-256.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-256.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-256.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-30.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-30.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-30.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-30.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-32.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-32.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-32.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-32.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-36.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-36.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-36.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-36.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-40.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-40.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-40.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-40.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-48.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-48.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-48.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-48.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-60.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-60.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-60.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-60.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-64.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-64.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-64.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-64.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-72.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-72.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-72.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-72.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-80.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-80.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-80.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-80.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-96.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-96.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-black_targetsize-96.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-black_targetsize-96.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_scale-125.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-125.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_scale-150.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-150.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_scale-400.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_scale-400.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-16.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-16.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-16.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-16.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-20.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-20.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-20.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-20.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-24.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-24.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-24.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-24.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-256.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-256.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-256.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-256.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-30.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-30.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-30.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-30.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-32.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-32.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-32.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-32.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-36.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-36.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-36.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-36.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-40.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-40.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-40.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-40.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-48.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-48.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-48.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-48.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-60.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-60.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-60.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-60.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-64.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-64.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-64.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-64.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-72.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-72.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-72.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-72.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-80.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-80.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-80.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-80.png diff --git a/src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-96.png b/src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-96.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.contrast-white_targetsize-96.png rename to src/Calculator.Shared/Assets/CalculatorAppList.contrast-white_targetsize-96.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-colorize.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-colorize.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-colorize.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-colorize.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-fullcolor.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-fullcolor.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-fullcolor.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-fullcolor.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-lightunplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-lightunplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-lightunplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-lightunplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-unplated.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-unplated.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-unplated.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-unplated.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png diff --git a/src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png b/src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png similarity index 100% rename from src/Calculator/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png rename to src/Calculator.Shared/Assets/CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-125.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-125.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-150.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-150.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-400.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-black_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-black_scale-400.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-125.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-125.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-150.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-150.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-400.png b/src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorLargeTile.contrast-white_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorLargeTile.contrast-white_scale-400.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-125.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-125.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-150.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-150.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-400.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-black_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-black_scale-400.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-125.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-125.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-150.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-150.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-400.png b/src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorMedTile.contrast-white_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorMedTile.contrast-white_scale-400.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-125.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-125.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-150.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-150.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-400.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-black_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-black_scale-400.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-125.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-125.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-150.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-150.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-400.png b/src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorSmallTile.contrast-white_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorSmallTile.contrast-white_scale-400.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-125.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-125.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-150.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-150.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-400.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-black_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-black_scale-400.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-125.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-125.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-150.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-150.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-400.png b/src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorSplashScreen.contrast-white_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorSplashScreen.contrast-white_scale-400.png diff --git a/src/Calculator/Assets/CalculatorStoreLogo.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorStoreLogo.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorStoreLogo.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorStoreLogo.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorStoreLogo.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorStoreLogo.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorStoreLogo.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorStoreLogo.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorStoreLogo.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-100.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-100.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-125.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-125.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-150.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-150.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-200.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-200.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-400.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-black_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-black_scale-400.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-100.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-100.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-100.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-100.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-125.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-125.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-125.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-125.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-150.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-150.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-150.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-150.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-200.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-200.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-200.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-200.png diff --git a/src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-400.png b/src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-400.png similarity index 100% rename from src/Calculator/Assets/CalculatorWideTile.contrast-white_scale-400.png rename to src/Calculator.Shared/Assets/CalculatorWideTile.contrast-white_scale-400.png diff --git a/src/Calculator/Assets/Date.targetsize-16_contrast-black.png b/src/Calculator.Shared/Assets/Date.targetsize-16_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-16_contrast-black.png rename to src/Calculator.Shared/Assets/Date.targetsize-16_contrast-black.png diff --git a/src/Calculator/Assets/Date.targetsize-16_contrast-white.png b/src/Calculator.Shared/Assets/Date.targetsize-16_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-16_contrast-white.png rename to src/Calculator.Shared/Assets/Date.targetsize-16_contrast-white.png diff --git a/src/Calculator/Assets/Date.targetsize-20_contrast-black.png b/src/Calculator.Shared/Assets/Date.targetsize-20_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-20_contrast-black.png rename to src/Calculator.Shared/Assets/Date.targetsize-20_contrast-black.png diff --git a/src/Calculator/Assets/Date.targetsize-20_contrast-white.png b/src/Calculator.Shared/Assets/Date.targetsize-20_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-20_contrast-white.png rename to src/Calculator.Shared/Assets/Date.targetsize-20_contrast-white.png diff --git a/src/Calculator/Assets/Date.targetsize-24_contrast-black.png b/src/Calculator.Shared/Assets/Date.targetsize-24_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-24_contrast-black.png rename to src/Calculator.Shared/Assets/Date.targetsize-24_contrast-black.png diff --git a/src/Calculator/Assets/Date.targetsize-24_contrast-white.png b/src/Calculator.Shared/Assets/Date.targetsize-24_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-24_contrast-white.png rename to src/Calculator.Shared/Assets/Date.targetsize-24_contrast-white.png diff --git a/src/Calculator/Assets/Date.targetsize-32_contrast-black.png b/src/Calculator.Shared/Assets/Date.targetsize-32_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-32_contrast-black.png rename to src/Calculator.Shared/Assets/Date.targetsize-32_contrast-black.png diff --git a/src/Calculator/Assets/Date.targetsize-32_contrast-white.png b/src/Calculator.Shared/Assets/Date.targetsize-32_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-32_contrast-white.png rename to src/Calculator.Shared/Assets/Date.targetsize-32_contrast-white.png diff --git a/src/Calculator/Assets/Date.targetsize-64_contrast-black.png b/src/Calculator.Shared/Assets/Date.targetsize-64_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-64_contrast-black.png rename to src/Calculator.Shared/Assets/Date.targetsize-64_contrast-black.png diff --git a/src/Calculator/Assets/Date.targetsize-64_contrast-white.png b/src/Calculator.Shared/Assets/Date.targetsize-64_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Date.targetsize-64_contrast-white.png rename to src/Calculator.Shared/Assets/Date.targetsize-64_contrast-white.png diff --git a/src/Calculator/Assets/Programmer.targetsize-16_contrast-black.png b/src/Calculator.Shared/Assets/Programmer.targetsize-16_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-16_contrast-black.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-16_contrast-black.png diff --git a/src/Calculator/Assets/Programmer.targetsize-16_contrast-white.png b/src/Calculator.Shared/Assets/Programmer.targetsize-16_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-16_contrast-white.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-16_contrast-white.png diff --git a/src/Calculator/Assets/Programmer.targetsize-20_contrast-black.png b/src/Calculator.Shared/Assets/Programmer.targetsize-20_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-20_contrast-black.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-20_contrast-black.png diff --git a/src/Calculator/Assets/Programmer.targetsize-20_contrast-white.png b/src/Calculator.Shared/Assets/Programmer.targetsize-20_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-20_contrast-white.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-20_contrast-white.png diff --git a/src/Calculator/Assets/Programmer.targetsize-24_contrast-black.png b/src/Calculator.Shared/Assets/Programmer.targetsize-24_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-24_contrast-black.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-24_contrast-black.png diff --git a/src/Calculator/Assets/Programmer.targetsize-24_contrast-white.png b/src/Calculator.Shared/Assets/Programmer.targetsize-24_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-24_contrast-white.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-24_contrast-white.png diff --git a/src/Calculator/Assets/Programmer.targetsize-32_contrast-black.png b/src/Calculator.Shared/Assets/Programmer.targetsize-32_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-32_contrast-black.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-32_contrast-black.png diff --git a/src/Calculator/Assets/Programmer.targetsize-32_contrast-white.png b/src/Calculator.Shared/Assets/Programmer.targetsize-32_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-32_contrast-white.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-32_contrast-white.png diff --git a/src/Calculator/Assets/Programmer.targetsize-64_contrast-black.png b/src/Calculator.Shared/Assets/Programmer.targetsize-64_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-64_contrast-black.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-64_contrast-black.png diff --git a/src/Calculator/Assets/Programmer.targetsize-64_contrast-white.png b/src/Calculator.Shared/Assets/Programmer.targetsize-64_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Programmer.targetsize-64_contrast-white.png rename to src/Calculator.Shared/Assets/Programmer.targetsize-64_contrast-white.png diff --git a/src/Calculator/Assets/Scientific.targetsize-16_contrast-black.png b/src/Calculator.Shared/Assets/Scientific.targetsize-16_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-16_contrast-black.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-16_contrast-black.png diff --git a/src/Calculator/Assets/Scientific.targetsize-16_contrast-white.png b/src/Calculator.Shared/Assets/Scientific.targetsize-16_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-16_contrast-white.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-16_contrast-white.png diff --git a/src/Calculator/Assets/Scientific.targetsize-20_contrast-black.png b/src/Calculator.Shared/Assets/Scientific.targetsize-20_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-20_contrast-black.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-20_contrast-black.png diff --git a/src/Calculator/Assets/Scientific.targetsize-20_contrast-white.png b/src/Calculator.Shared/Assets/Scientific.targetsize-20_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-20_contrast-white.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-20_contrast-white.png diff --git a/src/Calculator/Assets/Scientific.targetsize-24_contrast-black.png b/src/Calculator.Shared/Assets/Scientific.targetsize-24_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-24_contrast-black.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-24_contrast-black.png diff --git a/src/Calculator/Assets/Scientific.targetsize-24_contrast-white.png b/src/Calculator.Shared/Assets/Scientific.targetsize-24_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-24_contrast-white.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-24_contrast-white.png diff --git a/src/Calculator/Assets/Scientific.targetsize-32_contrast-black.png b/src/Calculator.Shared/Assets/Scientific.targetsize-32_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-32_contrast-black.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-32_contrast-black.png diff --git a/src/Calculator/Assets/Scientific.targetsize-32_contrast-white.png b/src/Calculator.Shared/Assets/Scientific.targetsize-32_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-32_contrast-white.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-32_contrast-white.png diff --git a/src/Calculator/Assets/Scientific.targetsize-64_contrast-black.png b/src/Calculator.Shared/Assets/Scientific.targetsize-64_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-64_contrast-black.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-64_contrast-black.png diff --git a/src/Calculator/Assets/Scientific.targetsize-64_contrast-white.png b/src/Calculator.Shared/Assets/Scientific.targetsize-64_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Scientific.targetsize-64_contrast-white.png rename to src/Calculator.Shared/Assets/Scientific.targetsize-64_contrast-white.png diff --git a/src/Calculator/Assets/Standard.targetsize-16_contrast-black.png b/src/Calculator.Shared/Assets/Standard.targetsize-16_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-16_contrast-black.png rename to src/Calculator.Shared/Assets/Standard.targetsize-16_contrast-black.png diff --git a/src/Calculator/Assets/Standard.targetsize-16_contrast-white.png b/src/Calculator.Shared/Assets/Standard.targetsize-16_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-16_contrast-white.png rename to src/Calculator.Shared/Assets/Standard.targetsize-16_contrast-white.png diff --git a/src/Calculator/Assets/Standard.targetsize-20_contrast-black.png b/src/Calculator.Shared/Assets/Standard.targetsize-20_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-20_contrast-black.png rename to src/Calculator.Shared/Assets/Standard.targetsize-20_contrast-black.png diff --git a/src/Calculator/Assets/Standard.targetsize-20_contrast-white.png b/src/Calculator.Shared/Assets/Standard.targetsize-20_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-20_contrast-white.png rename to src/Calculator.Shared/Assets/Standard.targetsize-20_contrast-white.png diff --git a/src/Calculator/Assets/Standard.targetsize-24_contrast-black.png b/src/Calculator.Shared/Assets/Standard.targetsize-24_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-24_contrast-black.png rename to src/Calculator.Shared/Assets/Standard.targetsize-24_contrast-black.png diff --git a/src/Calculator/Assets/Standard.targetsize-24_contrast-white.png b/src/Calculator.Shared/Assets/Standard.targetsize-24_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-24_contrast-white.png rename to src/Calculator.Shared/Assets/Standard.targetsize-24_contrast-white.png diff --git a/src/Calculator/Assets/Standard.targetsize-32_contrast-black.png b/src/Calculator.Shared/Assets/Standard.targetsize-32_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-32_contrast-black.png rename to src/Calculator.Shared/Assets/Standard.targetsize-32_contrast-black.png diff --git a/src/Calculator/Assets/Standard.targetsize-32_contrast-white.png b/src/Calculator.Shared/Assets/Standard.targetsize-32_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-32_contrast-white.png rename to src/Calculator.Shared/Assets/Standard.targetsize-32_contrast-white.png diff --git a/src/Calculator/Assets/Standard.targetsize-64_contrast-black.png b/src/Calculator.Shared/Assets/Standard.targetsize-64_contrast-black.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-64_contrast-black.png rename to src/Calculator.Shared/Assets/Standard.targetsize-64_contrast-black.png diff --git a/src/Calculator/Assets/Standard.targetsize-64_contrast-white.png b/src/Calculator.Shared/Assets/Standard.targetsize-64_contrast-white.png similarity index 100% rename from src/Calculator/Assets/Standard.targetsize-64_contrast-white.png rename to src/Calculator.Shared/Assets/Standard.targetsize-64_contrast-white.png diff --git a/src/Calculator.Shared/Assets/lockscreenlogo.scale-200.png b/src/Calculator.Shared/Assets/lockscreenlogo.scale-200.png new file mode 100644 index 00000000..735f57ad Binary files /dev/null and b/src/Calculator.Shared/Assets/lockscreenlogo.scale-200.png differ diff --git a/src/Calculator.Shared/Assets/splashscreen.scale-200.png b/src/Calculator.Shared/Assets/splashscreen.scale-200.png new file mode 100644 index 00000000..023e7f1f Binary files /dev/null and b/src/Calculator.Shared/Assets/splashscreen.scale-200.png differ diff --git a/src/Calculator.Shared/Assets/square150x150logo.scale-200.png b/src/Calculator.Shared/Assets/square150x150logo.scale-200.png new file mode 100644 index 00000000..af49fec1 Binary files /dev/null and b/src/Calculator.Shared/Assets/square150x150logo.scale-200.png differ diff --git a/src/Calculator.Shared/Assets/square44x44logo.scale-200.png b/src/Calculator.Shared/Assets/square44x44logo.scale-200.png new file mode 100644 index 00000000..ce342a2e Binary files /dev/null and b/src/Calculator.Shared/Assets/square44x44logo.scale-200.png differ diff --git a/src/Calculator.Shared/Assets/square44x44logo.targetsize-24_altform-unplated.png b/src/Calculator.Shared/Assets/square44x44logo.targetsize-24_altform-unplated.png new file mode 100644 index 00000000..f6c02ce9 Binary files /dev/null and b/src/Calculator.Shared/Assets/square44x44logo.targetsize-24_altform-unplated.png differ diff --git a/src/Calculator.Shared/Assets/storelogo.png b/src/Calculator.Shared/Assets/storelogo.png new file mode 100644 index 00000000..7385b56c Binary files /dev/null and b/src/Calculator.Shared/Assets/storelogo.png differ diff --git a/src/Calculator.Shared/Assets/wide310x150logo.scale-200.png b/src/Calculator.Shared/Assets/wide310x150logo.scale-200.png new file mode 100644 index 00000000..288995b3 Binary files /dev/null and b/src/Calculator.Shared/Assets/wide310x150logo.scale-200.png differ diff --git a/src/Calculator.Shared/CalcManager/CCalcEngine.cs b/src/Calculator.Shared/CalcManager/CCalcEngine.cs new file mode 100644 index 00000000..a59875a7 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/CCalcEngine.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; +using static CalculationManager.EngineStrings; +using static CalculationManager.CCommand; + +namespace CalculationManager +{ + class CCalcEngine + { + public static string OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype) => throw new NotImplementedException(); + public static string OpCodeToString(int nOpCode) => throw new NotImplementedException(); + } +} diff --git a/src/Calculator.Shared/CalcManager/CCommand.cs b/src/Calculator.Shared/CalcManager/CCommand.cs new file mode 100644 index 00000000..c0d5c7d6 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/CCommand.cs @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/****************************Module*Header*********************************** +* Module Name: CCommand.h +* +* Module Description: +* Resource ID's for the Engine Commands exposed. +* +* Warnings: +* +* Created: 13-Feb-2008 +* +\****************************************************************************/ + +// The following are the valid id's which can be passed to CCalcEngine::ProcessCommand + +namespace CalculationManager +{ + + public static class CCommand + { + public const int IDM_HEX = 313; + public const int IDM_DEC = 314; + public const int IDM_OCT = 315; + public const int IDM_BIN = 316; + public const int IDM_QWORD = 317; + public const int IDM_DWORD = 318; + public const int IDM_WORD = 319; + public const int IDM_BYTE = 320; + public const int IDM_DEG = 321; + public const int IDM_RAD = 322; + public const int IDM_GRAD = 323; + public const int IDM_DEGREES = 324; + + public const int IDC_HEX = IDM_HEX; + public const int IDC_DEC = IDM_DEC; + public const int IDC_OCT = IDM_OCT; + public const int IDC_BIN = IDM_BIN; + + public const int IDC_DEG = IDM_DEG; + public const int IDC_RAD = IDM_RAD; + public const int IDC_GRAD = IDM_GRAD; + public const int IDC_DEGREES = IDM_DEGREES; + + public const int IDC_QWORD = IDM_QWORD; + public const int IDC_DWORD = IDM_DWORD; + public const int IDC_WORD = IDM_WORD; + public const int IDC_BYTE = IDM_BYTE; + + // Key IDs: + // These id's must be consecutive from IDC_FIRSTCONTROL to IDC_LASTCONTROL. + // The actual values don't matter but the order and sequence are very important. + // Also, the order of the controls must match the order of the control names + // in the string table. + // For example you want to declare the color for the control IDC_ST_AVE + // Find the string id for that control from the rc file + // Now define the control's id as IDC_FRISTCONTROL+stringID(IDC_ST_AVE) + public const int IDC_FIRSTCONTROL = IDC_SIGN; + public const int IDC_SIGN = 80; + public const int IDC_CLEAR = 81; + public const int IDC_CENTR = 82; + public const int IDC_BACK = 83; + + public const int IDC_PNT = 84; + + // Hole 85 + + public const int IDC_AND = 86; // Binary operators must be between IDC_AND and IDC_PWR; + public const int IDC_OR = 87; + public const int IDC_XOR = 88; + public const int IDC_LSHF = 89; + public const int IDC_RSHF = 90; + public const int IDC_DIV = 91; + public const int IDC_MUL = 92; + public const int IDC_ADD = 93; + public const int IDC_SUB = 94; + public const int IDC_MOD = 95; + public const int IDC_ROOT = 96; + public const int IDC_PWR = 97; + + public const int IDC_UNARYFIRST = IDC_CHOP; + public const int IDC_CHOP = 98; // Unary operators must be between IDC_CHOP and IDC_EQU; + public const int IDC_ROL = 99; + public const int IDC_ROR = 100; + public const int IDC_COM = 101; + public const int IDC_SIN = 102; + public const int IDC_COS = 103; + public const int IDC_TAN = 104; + + public const int IDC_SINH = 105; + public const int IDC_COSH = 106; + public const int IDC_TANH = 107; + + public const int IDC_LN = 108; + public const int IDC_LOG = 109; + public const int IDC_SQRT = 110; + public const int IDC_SQR = 111; + public const int IDC_CUB = 112; + public const int IDC_FAC = 113; + public const int IDC_REC = 114; + public const int IDC_DMS = 115; + public const int IDC_CUBEROOT = 116; // x ^ 1/3; + public const int IDC_POW10 = 117; // 10 ^ x; + public const int IDC_PERCENT = 118; + public const int IDC_UNARYLAST = IDC_PERCENT; + + public const int IDC_FE = 119; + public const int IDC_PI = 120; + public const int IDC_EQU = 121; + + public const int IDC_MCLEAR = 122; + public const int IDC_RECALL = 123; + public const int IDC_STORE = 124; + public const int IDC_MPLUS = 125; + public const int IDC_MMINUS = 126; + + public const int IDC_EXP = 127; + + public const int IDC_OPENP = 128; + public const int IDC_CLOSEP = 129; + + public const int IDC_0 = 130; // The controls for 0 through F must be consecutive and in order; + public const int IDC_1 = 131; + public const int IDC_2 = 132; + public const int IDC_3 = 133; + public const int IDC_4 = 134; + public const int IDC_5 = 135; + public const int IDC_6 = 136; + public const int IDC_7 = 137; + public const int IDC_8 = 138; + public const int IDC_9 = 139; + public const int IDC_A = 140; + public const int IDC_B = 141; + public const int IDC_C = 142; + public const int IDC_D = 143; + public const int IDC_E = 144; + public const int IDC_F = 145; // this is last control ID which must match the string table; + public const int IDC_INV = 146; + public const int IDC_SET_RESULT = 147; + + public const int IDC_LASTCONTROL = IDC_SET_RESULT; + + public const int IDC_BINEDITSTART = 700; + public const int IDC_BINPOS0 = 700; + public const int IDC_BINPOS1 = 701; + public const int IDC_BINPOS2 = 702; + public const int IDC_BINPOS3 = 703; + public const int IDC_BINPOS4 = 704; + public const int IDC_BINPOS5 = 705; + public const int IDC_BINPOS6 = 706; + public const int IDC_BINPOS7 = 707; + public const int IDC_BINPOS8 = 708; + public const int IDC_BINPOS9 = 709; + public const int IDC_BINPOS10 = 710; + public const int IDC_BINPOS11 = 711; + public const int IDC_BINPOS12 = 712; + public const int IDC_BINPOS13 = 713; + public const int IDC_BINPOS14 = 714; + public const int IDC_BINPOS15 = 715; + public const int IDC_BINPOS16 = 716; + public const int IDC_BINPOS17 = 717; + public const int IDC_BINPOS18 = 718; + public const int IDC_BINPOS19 = 719; + public const int IDC_BINPOS20 = 720; + public const int IDC_BINPOS21 = 721; + public const int IDC_BINPOS22 = 722; + public const int IDC_BINPOS23 = 723; + public const int IDC_BINPOS24 = 724; + public const int IDC_BINPOS25 = 725; + public const int IDC_BINPOS26 = 726; + public const int IDC_BINPOS27 = 727; + public const int IDC_BINPOS28 = 728; + public const int IDC_BINPOS29 = 729; + public const int IDC_BINPOS30 = 730; + public const int IDC_BINPOS31 = 731; + public const int IDC_BINPOS32 = 732; + public const int IDC_BINPOS33 = 733; + public const int IDC_BINPOS34 = 734; + public const int IDC_BINPOS35 = 735; + public const int IDC_BINPOS36 = 736; + public const int IDC_BINPOS37 = 737; + public const int IDC_BINPOS38 = 738; + public const int IDC_BINPOS39 = 739; + public const int IDC_BINPOS40 = 740; + public const int IDC_BINPOS41 = 741; + public const int IDC_BINPOS42 = 742; + public const int IDC_BINPOS43 = 743; + public const int IDC_BINPOS44 = 744; + public const int IDC_BINPOS45 = 745; + public const int IDC_BINPOS46 = 746; + public const int IDC_BINPOS47 = 747; + public const int IDC_BINPOS48 = 748; + public const int IDC_BINPOS49 = 749; + public const int IDC_BINPOS50 = 750; + public const int IDC_BINPOS51 = 751; + public const int IDC_BINPOS52 = 752; + public const int IDC_BINPOS53 = 753; + public const int IDC_BINPOS54 = 754; + public const int IDC_BINPOS55 = 755; + public const int IDC_BINPOS56 = 756; + public const int IDC_BINPOS57 = 757; + public const int IDC_BINPOS58 = 758; + public const int IDC_BINPOS59 = 759; + public const int IDC_BINPOS60 = 760; + public const int IDC_BINPOS61 = 761; + public const int IDC_BINPOS62 = 762; + public const int IDC_BINPOS63 = 763; + public const int IDC_BINEDITEND = 763; + + // The strings in the following range IDS_ENGINESTR_FIRST ... IDS_ENGINESTR_MAX are strings allocated in the + // resource for the purpose internal to Engine and cant be used by the clients + public const int IDS_ENGINESTR_FIRST = 0; + public const int IDS_ENGINESTR_MAX = 200; + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/CalcManager/CalculatorList.cs b/src/Calculator.Shared/CalcManager/CalculatorList.cs new file mode 100644 index 00000000..ecbbb09f --- /dev/null +++ b/src/Calculator.Shared/CalcManager/CalculatorList.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculatorApp +{ + public class CalculatorList + { + List m_vector; + + public CalculatorList() + { + m_vector = new List(); + } + + public CalculatorList(CalculatorList source) + { + m_vector = new List(source.m_vector); + } + + public bool GetAt(int index, out TType item) + { + item = m_vector[index]; + return true; + } + + public bool GetSize(out int size) + { + size = m_vector.Count; + return true; + } + + public bool SetAt(int index, TType item) + { + m_vector[index] = item; + return true; + } + + public bool RemoveAt(int index) + { + if (index < m_vector.Count) + { + m_vector.RemoveAt(index); + } + else + { + throw new ArgumentOutOfRangeException(); + } + + return true; + } + + public bool InsertAt(int index, TType item) + { + m_vector.Insert(index, item); + return true; + } + + public bool Truncate(int index) + { + if (index < m_vector.Count) + { + m_vector.RemoveRange(index, m_vector.Count - index); + } + else + { + throw new ArgumentOutOfRangeException(); + } + return true; + } + + public bool Append(TType item) + { + m_vector.Add(item); + return true; + } + + public bool RemoveAtEnd() + { + m_vector.RemoveAt(m_vector.Count - 1); + return true; + } + + public bool Clear() + { + m_vector.Clear(); + return true; + } + + public bool GetString(out string expression) + { + // UNO TODO + //int nTokens = 0; + //(string, int) currentPair; + //var hr = this.GetSize(out nTokens); + //if (hr) + //{ + // for (int i = 0; i < nTokens; i++) + // { + // hr = this.GetAt(i, out currentPair); + // if ((hr)) + // { + // expression.append(currentPair.first); + + // if (i != (nTokens - 1)) + // { + // expression.append(" "); + // } + // } + // } + + // string expressionSuffix; + // hr = GetExpressionSuffix(&expressionSuffix); + // if (hr) + // { + // expression += expressionSuffix; + // } + //} + + // return true; + + expression = ""; + return false; + } + + public bool GetExpressionSuffix(out string suffix) + { + suffix = " ="; + return true; + } + } +} diff --git a/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs b/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs new file mode 100644 index 00000000..cfd5b643 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using CalculatorApp; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace CalculationManager +{ + public partial class CalculatorManager : ICalcDisplay + { + [DllImport("CalcManager")] + public static extern IntPtr CalculatorManager_Create(ref CalculatorManager_CreateParams parms); + + [DllImport("CalcManager")] + public static extern void CalculatorManager_SendCommand(IntPtr instance, Command command); + + private delegate IntPtr GetCEngineStringFunc(IntPtr state, string id); + private delegate void BinaryOperatorReceivedFunc(IntPtr state); + private delegate void SetPrimaryDisplayCallbackFunc(IntPtr state, string displayStringValue, bool isError); + private delegate void SetIsInErrorCallbackFunc(IntPtr state, bool isError); + private delegate void SetParenthesisNumberCallbackFunc(IntPtr state, int parenthesisCount); + + private delegate void MaxDigitsReachedCallbackFunc(IntPtr state); + private delegate void MemoryItemChangedCallbackFunc(IntPtr state, int indexOfMemory); + private delegate void OnHistoryItemAddedCallbackFunc(IntPtr state, int addedItemIndex); + private delegate void OnNoRightParenAddedCallbackFunc(IntPtr state); + private delegate void SetExpressionDisplayCallbackFunc(IntPtr state); + private delegate void SetMemorizedNumbersCallbackFunc(IntPtr state, string[] newMemorizedNumbers); + + private static GetCEngineStringFunc _getCEngineStringCallback = GetCEngineStringCallback; + private static BinaryOperatorReceivedFunc _binaryOperatorReceivedCallback = BinaryOperatorReceivedCallback; + private static SetPrimaryDisplayCallbackFunc _setPrimaryDisplayCallback = SetPrimaryDisplayCallback; + private static SetIsInErrorCallbackFunc _setIsInErrorCallback = SetIsInErrorCallback; + private static SetParenthesisNumberCallbackFunc _setParenthesisNumberCallback = SetParenthesisNumberCallback; + + private static MaxDigitsReachedCallbackFunc _maxDigitsReachedCallback = MaxDigitsReachedCallback; + private static MemoryItemChangedCallbackFunc _memoryItemChangedCallback = MemoryItemChangedCallback; + private static OnHistoryItemAddedCallbackFunc _onHistoryItemAddedCallback = OnHistoryItemAddedCallback; + private static OnNoRightParenAddedCallbackFunc _onNoRightParenAddedCallback = OnNoRightParenAddedCallback; + private static SetExpressionDisplayCallbackFunc _setExpressionDisplayCallback = SetExpressionDisplayCallback; + private static SetMemorizedNumbersCallbackFunc _setMemorizedNumbersCallback = SetMemorizedNumbersCallback; + + private GCHandle _displayCallbackHandle; + private GCHandle _resourceProviderHandle; + private readonly IntPtr _nativeManager; + + private static void MaxDigitsReachedCallback(IntPtr state) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.MaxDigitsReached(); + + Debug.WriteLine($"CalculatorManager.MaxDigitsReachedCallback"); + } + + private static void MemoryItemChangedCallback(IntPtr state, int indexOfMemory) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.MemoryItemChanged(indexOfMemory); + + Debug.WriteLine($"CalculatorManager.MemoryItemChangedCallback({indexOfMemory})"); + } + + private static void OnHistoryItemAddedCallback(IntPtr state, int addedItemIndex) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.OnHistoryItemAdded(addedItemIndex); + + Debug.WriteLine($"CalculatorManager.OnHistoryItemAddedCallback({addedItemIndex})"); + } + + private static void OnNoRightParenAddedCallback(IntPtr state) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.OnNoRightParenAdded(); + + Debug.WriteLine($"CalculatorManager.OnNoRightParenAddedCallback"); + } + + private static void SetExpressionDisplayCallback(IntPtr state) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + // manager.SetExpressionDisplay(); + + Debug.WriteLine($"CalculatorManager.SetExpressionDisplayCallback"); + } + + private static void SetMemorizedNumbersCallback(IntPtr state, string[] newMemorizedNumbers) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.SetMemorizedNumbers(newMemorizedNumbers.ToList()); + + Debug.WriteLine($"CalculatorManager.SetMemorizedNumbersCallback({string.Join(";", newMemorizedNumbers)})"); + } + + private static void SetParenthesisNumberCallback(IntPtr state, int parenthesisCount) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.SetParenthesisNumber(parenthesisCount); + + Debug.WriteLine($"CalculatorManager.SetParenthesisNumberCallback({parenthesisCount})"); + } + + private static void BinaryOperatorReceivedCallback(IntPtr state) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.BinaryOperatorReceived(); + + Debug.WriteLine($"CalculatorManager.BinaryOperatorReceivedCallback"); + } + + private static void SetPrimaryDisplayCallback(IntPtr state, string displayStringValue, bool isError) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.SetPrimaryDisplay(displayStringValue, isError); + + Debug.WriteLine($"CalculatorManager.SetPrimaryDisplayCallback({displayStringValue}, {isError})"); + } + + private static void SetIsInErrorCallback(IntPtr state, bool isError) + { + var manager = GCHandle.FromIntPtr(state).Target as CalculatorDisplay; + manager.SetIsInError(isError); + + Debug.WriteLine($"CalculatorManager.SetIsInErrorCallback({isError})"); + } + + private static IntPtr GetCEngineStringCallback(IntPtr state, string resourceId) + { + var provider = GCHandle.FromIntPtr(state).Target as EngineResourceProvider; + var ret = provider.GetCEngineString(resourceId) ?? ""; + + var retBytes = Encoding.UTF8.GetBytes(ret); + var retPtr = Marshal.AllocHGlobal(retBytes.Length+1); + Marshal.WriteByte(retPtr + retBytes.Length, 0); + Marshal.Copy(retBytes, 0, retPtr, retBytes.Length); + + Debug.WriteLine($"CalculatorManager.GetCEngineStringCallback({resourceId},{ret})"); + + return retPtr; + } + } +} diff --git a/src/Calculator.Shared/CalcManager/CalculatorManager.cs b/src/Calculator.Shared/CalcManager/CalculatorManager.cs new file mode 100644 index 00000000..46a8241e --- /dev/null +++ b/src/Calculator.Shared/CalcManager/CalculatorManager.cs @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using CalculatorApp; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace CalculationManager +{ + + public enum CalculatorPrecision + { + StandardModePrecision = 16, + ScientificModePrecision = 32, + ProgrammerModePrecision = 64 + }; + + // Numbering continues from the Enum Command from Command.h + // with some gap to ensure there is no overlap of these ids + // when (unsigned char) is performed on these ids + // they shouldn't fall in any number range greater than 80. So never + // make the memory command ids go below 330 + public enum MemoryCommand + { + MemorizeNumber = 330, + MemorizedNumberLoad = 331, + MemorizedNumberAdd = 332, + MemorizedNumberSubtract = 333, + MemorizedNumberClearAll = 334, + MemorizedNumberClear = 335 + }; + + public struct HISTORYITEMVECTOR + { + public CalculatorList<(string, int)> spTokens; + public CalculatorList spCommands; + public string expression; + public string result; + }; + + public struct HISTORYITEM + { + public HISTORYITEMVECTOR historyItemVector; + }; + + public interface ICalcDisplay + { + void SetPrimaryDisplay(string pszText, bool isError); + void SetIsInError(bool isInError); + void SetExpressionDisplay( + CalculatorList<(string, int)> tokens, + CalculatorList commands); + void SetParenthesisNumber( int count); + void OnNoRightParenAdded(); + void MaxDigitsReached(); // not an error but still need to inform UI layer. + void BinaryOperatorReceived(); + void OnHistoryItemAdded( int addedItemIndex); + void SetMemorizedNumbers(List memorizedNumbers); + void MemoryItemChanged(int indexOfMemory); + } + + [StructLayout(LayoutKind.Sequential)] + public struct CalculatorManager_CreateParams + { + public IntPtr CalculatorState; + + public IntPtr SetPrimaryDisplay; + public IntPtr SetIsInError; + public IntPtr SetExpressionDisplay; + public IntPtr SetParenthesisNumber; + public IntPtr OnNoRightParenAdded; + public IntPtr MaxDigitsReached; + public IntPtr BinaryOperatorReceived; + public IntPtr OnHistoryItemAdded; + public IntPtr SetMemorizedNumbers; + public IntPtr MemoryItemChanged; + + public IntPtr ResourceState; + + public IntPtr GetCEngineString; + }; + + public partial class CalculatorManager : ICalcDisplay + { + public void SetPrimaryDisplay(string displayString, bool isError) => throw new NotImplementedException(); + public void SetIsInError(bool isError) => throw new NotImplementedException(); + public void SetExpressionDisplay( + CalculatorList<(string, int)> tokens, + CalculatorList commands) => throw new NotImplementedException(); + public void SetMemorizedNumbers(List memorizedNumbers) => throw new NotImplementedException(); + public void OnHistoryItemAdded(int addedItemIndex) => throw new NotImplementedException(); + public void SetParenthesisNumber(int parenthesisCount) => throw new NotImplementedException(); + public void OnNoRightParenAdded() => throw new NotImplementedException(); + public void DisplayPasteError() => throw new NotImplementedException(); + public void MaxDigitsReached() => throw new NotImplementedException(); + public void BinaryOperatorReceived() => throw new NotImplementedException(); + public void MemoryItemChanged(int indexOfMemory) => throw new NotImplementedException(); + + public CalculatorManager(ref CalculatorDisplay displayCallback, ref EngineResourceProvider resourceProvider) + { + Debug.WriteLine($"new CalculatorManager"); + displayCallback = new CalculatorDisplay(); + resourceProvider = new EngineResourceProvider(); + + _displayCallbackHandle = GCHandle.Alloc(displayCallback); + _resourceProviderHandle = GCHandle.Alloc(resourceProvider); + + var p = new CalculatorManager_CreateParams + { + CalculatorState = GCHandle.ToIntPtr(_displayCallbackHandle), + GetCEngineString = Marshal.GetFunctionPointerForDelegate(_getCEngineStringCallback), + + ResourceState = GCHandle.ToIntPtr(_resourceProviderHandle), + BinaryOperatorReceived = Marshal.GetFunctionPointerForDelegate(_binaryOperatorReceivedCallback), + SetPrimaryDisplay = Marshal.GetFunctionPointerForDelegate(_setPrimaryDisplayCallback), + SetIsInError = Marshal.GetFunctionPointerForDelegate(_setIsInErrorCallback), + SetParenthesisNumber = Marshal.GetFunctionPointerForDelegate(_setParenthesisNumberCallback), + MaxDigitsReached = Marshal.GetFunctionPointerForDelegate(_maxDigitsReachedCallback), + MemoryItemChanged = Marshal.GetFunctionPointerForDelegate(_memoryItemChangedCallback), + OnHistoryItemAdded = Marshal.GetFunctionPointerForDelegate(_onHistoryItemAddedCallback), + OnNoRightParenAdded = Marshal.GetFunctionPointerForDelegate(_onNoRightParenAddedCallback), + SetExpressionDisplay = Marshal.GetFunctionPointerForDelegate(_setExpressionDisplayCallback), + SetMemorizedNumbers = Marshal.GetFunctionPointerForDelegate(_setMemorizedNumbersCallback), + }; + + _nativeManager = CalculatorManager_Create(ref p); + } + + public void Reset(bool clearMemory = true) => throw new NotImplementedException(); + public void SetStandardMode() => throw new NotImplementedException(); + public void SetScientificMode() => throw new NotImplementedException(); + public void SetProgrammerMode() => throw new NotImplementedException(); + public void SendCommand(Command command) + { + Debug.WriteLine($"CalculatorManager.SendCommand({command})"); + + CalculatorManager_SendCommand(_nativeManager, command); + } + + public List SerializeCommands() => throw new NotImplementedException(); + public void DeSerializeCommands(List serializedData) => throw new NotImplementedException(); + public void SerializeMemory() => throw new NotImplementedException(); + public List GetSerializedMemory() => throw new NotImplementedException(); + public void DeSerializeMemory(List serializedMemory) => throw new NotImplementedException(); + public void SerializePrimaryDisplay() => throw new NotImplementedException(); + public List GetSerializedPrimaryDisplay() => throw new NotImplementedException(); + public void DeSerializePrimaryDisplay(List serializedPrimaryDisplay) => throw new NotImplementedException(); + public Command SerializeSavedDegreeMode() => throw new NotImplementedException(); + + public void MemorizeNumber() => throw new NotImplementedException(); + public void MemorizedNumberLoad(int value) + { + Debug.WriteLine($"CalculatorManager.MemorizedNumberLoad({value})"); + } + public void MemorizedNumberAdd(int value) + { + Debug.WriteLine($"CalculatorManager.MemorizedNumberAdd({value})"); + } + public void MemorizedNumberSubtract(int value) + { + Debug.WriteLine($"CalculatorManager.MemorizedNumberSubtract({value})"); + } + public void MemorizedNumberClear(int value) + { + Debug.WriteLine($"CalculatorManager.MemorizedNumberClear({value})"); + } + public void MemorizedNumberClearAll() + { + Debug.WriteLine($"CalculatorManager.MemorizedNumberClearAll()"); + } + + public bool IsEngineRecording() => throw new NotImplementedException(); + public List GetSavedCommands() => throw new NotImplementedException(); + public void SetRadix(RADIX_TYPE iRadixType) + { + Debug.WriteLine($"CalculatorManager.SetRadix({iRadixType})"); + } + public void SetMemorizedNumbersString() => throw new NotImplementedException(); + public string GetResultForRadix(int radix, int precision) => throw new NotImplementedException(); + public void SetPrecision(int precision) + { + Debug.WriteLine($"CalculatorManager.SetPrecision({precision})"); + } + public void UpdateMaxIntDigits() + { + Debug.WriteLine($"CalculatorManager.UpdateMaxIntDigits()"); + } + public char DecimalSeparator() => throw new NotImplementedException(); + + public List GetHistoryItems() => throw new NotImplementedException(); + + public List GetHistoryItems(CalculationManager.CALCULATOR_MODE mode) + { + Debug.WriteLine($"CalculatorManager.GetHistoryItems({mode})"); + + return new List(); + } + + public HISTORYITEM GetHistoryItem(int uIdx) => throw new NotImplementedException(); + public bool RemoveHistoryItem(int uIdx) => throw new NotImplementedException(); + public void ClearHistory() => throw new NotImplementedException(); + public int MaxHistorySize() => throw new NotImplementedException(); + public CalculationManager.Command GetCurrentDegreeMode() => throw new NotImplementedException(); + public void SetHistory(CALCULATOR_MODE eMode, List history) => throw new NotImplementedException(); + public void SetInHistoryItemLoadMode(bool isHistoryItemLoadMode) => throw new NotImplementedException(); + } +} diff --git a/src/Calculator.Shared/CalcManager/CalculatorMode.cs b/src/Calculator.Shared/CalcManager/CalculatorMode.cs new file mode 100644 index 00000000..fe72a02a --- /dev/null +++ b/src/Calculator.Shared/CalcManager/CalculatorMode.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculationManager +{ + public enum CALCULATOR_MODE + { + CM_STD = 0, + CM_SCI, + }; +} diff --git a/src/Calculator.Shared/CalcManager/Command.cs b/src/Calculator.Shared/CalcManager/Command.cs new file mode 100644 index 00000000..6bb5b3c8 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/Command.cs @@ -0,0 +1,244 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace UnitConversionManager +{ + public enum Command + { + Zero, + One, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + Decimal, + Negate, + Backspace, + Clear, + Reset, + None + } +} + +namespace CurrencyConversionManager +{ + public enum Command + { + Zero, + One, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + Decimal, + Negate, + Backspace, + Clear, + None + }; +} + +namespace CalculationManager +{ + public enum CommandType + { + UnaryCommand, + BinaryCommand, + OperandCommand, + Parentheses + }; + + public enum Command + { + // Commands for programmer calculators are omitted. + CommandDEG = 321, + CommandRAD = 322, + CommandGRAD = 323, + CommandDegrees = 324, + CommandHYP = 325, + + CommandNULL = 0, + + // No new command should not be added before CommandSign, 80 + // If it is needed, the following two functions need to be revised too. + // CalculatorManager::MapCommandForSerialize(Command command); + // CalculatorManager::MapCommandForDeSerialize(unsigned char command); + CommandSIGN = 80, + CommandCLEAR = 81, + CommandCENTR = 82, + CommandBACK = 83, + + CommandPNT = 84, + + // Hole 85 + // Unused commands defined in Command.h is omitted. + CommandXor = 88, + CommandLSHF = 89, + CommandRSHF = 90, + CommandDIV = 91, + CommandMUL = 92, + CommandADD = 93, + CommandSUB = 94, + CommandMOD = 95, + CommandROOT = 96, + CommandPWR = 97, + + CommandCHOP = 98, // Unary operators must be between CommandCHOP and CommandEQU + CommandROL = 99, + CommandROR = 100, + CommandCOM = 101, + CommandSIN = 102, + CommandCOS = 103, + CommandTAN = 104, + + CommandSINH = 105, + CommandCOSH = 106, + CommandTANH = 107, + + CommandLN = 108, + CommandLOG = 109, + CommandSQRT = 110, + CommandSQR = 111, + CommandCUB = 112, + CommandFAC = 113, + CommandREC = 114, + CommandDMS = 115, + CommandCUBEROOT = 116, // x ^ 1/3 + CommandPOW10 = 117, // 10 ^ x + CommandPERCENT = 118, + + CommandFE = 119, + CommandPI = 120, + CommandEQU = 121, + + CommandMCLEAR = 122, + CommandRECALL = 123, + CommandSTORE = 124, + CommandMPLUS = 125, + CommandMMINUS = 126, + + CommandEXP = 127, + + CommandOPENP = 128, + CommandCLOSEP = 129, + + Command0 = 130, // The controls for 0 through F must be consecutive and in order + Command1 = 131, + Command2 = 132, + Command3 = 133, + Command4 = 134, + Command5 = 135, + Command6 = 136, + Command7 = 137, + Command8 = 138, + Command9 = 139, + CommandA = 140, + CommandB = 141, + CommandC = 142, + CommandD = 143, + CommandE = 144, + CommandF = 145, // this is last control ID which must match the string table + CommandINV = 146, + CommandSET_RESULT = 147, + + CommandAnd = 86, + CommandOR = 87, + CommandNot = 101, + + ModeBasic = 200, + ModeScientific = 201, + + CommandASIN = 202, + CommandACOS = 203, + CommandATAN = 204, + CommandPOWE = 205, + CommandASINH = 206, + CommandACOSH = 207, + CommandATANH = 208, + + ModeProgrammer = 209, + CommandHex = 313, + CommandDec = 314, + CommandOct = 315, + CommandBin = 316, + CommandQword = 317, + CommandDword = 318, + CommandWord = 319, + CommandByte = 320, + + CommandBINEDITSTART = 700, + CommandBINPOS0 = 700, + CommandBINPOS1 = 701, + CommandBINPOS2 = 702, + CommandBINPOS3 = 703, + CommandBINPOS4 = 704, + CommandBINPOS5 = 705, + CommandBINPOS6 = 706, + CommandBINPOS7 = 707, + CommandBINPOS8 = 708, + CommandBINPOS9 = 709, + CommandBINPOS10 = 710, + CommandBINPOS11 = 711, + CommandBINPOS12 = 712, + CommandBINPOS13 = 713, + CommandBINPOS14 = 714, + CommandBINPOS15 = 715, + CommandBINPOS16 = 716, + CommandBINPOS17 = 717, + CommandBINPOS18 = 718, + CommandBINPOS19 = 719, + CommandBINPOS20 = 720, + CommandBINPOS21 = 721, + CommandBINPOS22 = 722, + CommandBINPOS23 = 723, + CommandBINPOS24 = 724, + CommandBINPOS25 = 725, + CommandBINPOS26 = 726, + CommandBINPOS27 = 727, + CommandBINPOS28 = 728, + CommandBINPOS29 = 729, + CommandBINPOS30 = 730, + CommandBINPOS31 = 731, + CommandBINPOS32 = 732, + CommandBINPOS33 = 733, + CommandBINPOS34 = 734, + CommandBINPOS35 = 735, + CommandBINPOS36 = 736, + CommandBINPOS37 = 737, + CommandBINPOS38 = 738, + CommandBINPOS39 = 739, + CommandBINPOS40 = 740, + CommandBINPOS41 = 741, + CommandBINPOS42 = 742, + CommandBINPOS43 = 743, + CommandBINPOS44 = 744, + CommandBINPOS45 = 745, + CommandBINPOS46 = 746, + CommandBINPOS47 = 747, + CommandBINPOS48 = 748, + CommandBINPOS49 = 749, + CommandBINPOS50 = 750, + CommandBINPOS51 = 751, + CommandBINPOS52 = 752, + CommandBINPOS53 = 753, + CommandBINPOS54 = 754, + CommandBINPOS55 = 755, + CommandBINPOS56 = 756, + CommandBINPOS57 = 757, + CommandBINPOS58 = 758, + CommandBINPOS59 = 759, + CommandBINPOS60 = 760, + CommandBINPOS61 = 761, + CommandBINPOS62 = 762, + CommandBINPOS63 = 763, + CommandBINEDITEND = 763 + }; +} \ No newline at end of file diff --git a/src/Calculator.Shared/CalcManager/EngineStrings.cs b/src/Calculator.Shared/CalcManager/EngineStrings.cs new file mode 100644 index 00000000..27d08ca3 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/EngineStrings.cs @@ -0,0 +1,300 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/****************************Module*Header*********************************** +* Module Name: EngineStrings.h +* +* Module Description: +* Resource String ID's for the private strings used by Engine. Internal to Engine related code +* not required by the clients +* +* Warnings: +* +* Created: 13-Feb-2008 +* +\****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculationManager +{ + public static class EngineStrings + { + public const int IDS_ERRORS_FIRST = 99; + + // This is the list of error strings corresponding to SCERR_DIVIDEZERO.. + + public const int IDS_DIVBYZERO = IDS_ERRORS_FIRST; + public const int IDS_DOMAIN = IDS_ERRORS_FIRST + 1; + public const int IDS_UNDEFINED = IDS_ERRORS_FIRST + 2; + public const int IDS_POS_INFINITY = IDS_ERRORS_FIRST + 3; + public const int IDS_NEG_INFINITY = IDS_ERRORS_FIRST + 4; + public const int IDS_NOMEM = IDS_ERRORS_FIRST + 6; + public const int IDS_TOOMANY = IDS_ERRORS_FIRST + 7; + public const int IDS_OVERFLOW = IDS_ERRORS_FIRST + 8; + public const int IDS_NORESULT = IDS_ERRORS_FIRST + 9; + public const int IDS_INSUFFICIENT_DATA = IDS_ERRORS_FIRST + 10; + + public const int CSTRINGSENGMAX = IDS_INSUFFICIENT_DATA + 1; + + // Arithmetic expression evaluator error strings + public const int IDS_ERR_UNK_CH = CSTRINGSENGMAX + 1; + public const int IDS_ERR_UNK_FN = CSTRINGSENGMAX + 2; + public const int IDS_ERR_UNEX_NUM = CSTRINGSENGMAX + 3; + public const int IDS_ERR_UNEX_CH = CSTRINGSENGMAX + 4; + public const int IDS_ERR_UNEX_SZ = CSTRINGSENGMAX + 5; + public const int IDS_ERR_MISMATCH_CLOSE = CSTRINGSENGMAX + 6; + public const int IDS_ERR_UNEX_END = CSTRINGSENGMAX + 7; + public const int IDS_ERR_SG_INV_ERROR = CSTRINGSENGMAX + 8; + public const int IDS_ERR_INPUT_OVERFLOW = CSTRINGSENGMAX + 9; + public const int IDS_ERR_OUTPUT_OVERFLOW = CSTRINGSENGMAX + 10; + + // Resource keys for CEngineStrings.resw + public const string SIDS_PLUS_MINUS = "0"; + public const string SIDS_CLEAR = "1"; + public const string SIDS_CE = "2"; + public const string SIDS_BACKSPACE = "3"; + public const string SIDS_DECIMAL_SEPARATOR = "4"; + public const string SIDS_EMPTY_STRING = "5"; + public const string SIDS_AND = "6"; + public const string SIDS_OR = "7"; + public const string SIDS_XOR = "8"; + public const string SIDS_LSH = "9"; + public const string SIDS_RSH = "10"; + public const string SIDS_DIVIDE = "11"; + public const string SIDS_MULTIPLY = "12"; + public const string SIDS_PLUS = "13"; + public const string SIDS_MINUS = "14"; + public const string SIDS_MOD = "15"; + public const string SIDS_YROOT = "16"; + public const string SIDS_POW_HAT = "17"; + public const string SIDS_INT = "18"; + public const string SIDS_ROL = "19"; + public const string SIDS_ROR = "20"; + public const string SIDS_NOT = "21"; + public const string SIDS_SIN = "22"; + public const string SIDS_COS = "23"; + public const string SIDS_TAN = "24"; + public const string SIDS_SINH = "25"; + public const string SIDS_COSH = "26"; + public const string SIDS_TANH = "27"; + public const string SIDS_LN = "28"; + public const string SIDS_LOG = "29"; + public const string SIDS_SQRT = "30"; + public const string SIDS_XPOW2 = "31"; + public const string SIDS_XPOW3 = "32"; + public const string SIDS_NFACTORIAL = "33"; + public const string SIDS_RECIPROCAL = "34"; + public const string SIDS_DMS = "35"; + public const string SIDS_CUBEROOT = "36"; + public const string SIDS_POWTEN = "37"; + public const string SIDS_PERCENT = "38"; + public const string SIDS_SCIENTIFIC_NOTATION = "39"; + public const string SIDS_PI = "40"; + public const string SIDS_EQUAL = "41"; + public const string SIDS_MC = "42"; + public const string SIDS_MR = "43"; + public const string SIDS_MS = "44"; + public const string SIDS_MPLUS = "45"; + public const string SIDS_MMINUS = "46"; + public const string SIDS_EXP = "47"; + public const string SIDS_OPEN_PAREN = "48"; + public const string SIDS_CLOSE_PAREN = "49"; + public const string SIDS_0 = "50"; + public const string SIDS_1 = "51"; + public const string SIDS_2 = "52"; + public const string SIDS_3 = "53"; + public const string SIDS_4 = "54"; + public const string SIDS_5 = "55"; + public const string SIDS_6 = "56"; + public const string SIDS_7 = "57"; + public const string SIDS_8 = "58"; + public const string SIDS_9 = "59"; + public const string SIDS_A = "60"; + public const string SIDS_B = "61"; + public const string SIDS_C = "62"; + public const string SIDS_D = "63"; + public const string SIDS_E = "64"; + public const string SIDS_F = "65"; + public const string SIDS_FRAC = "66"; + public const string SIDS_SIND = "67"; + public const string SIDS_COSD = "68"; + public const string SIDS_TAND = "69"; + public const string SIDS_ASIND = "70"; + public const string SIDS_ACOSD = "71"; + public const string SIDS_ATAND = "72"; + public const string SIDS_SINR = "73"; + public const string SIDS_COSR = "74"; + public const string SIDS_TANR = "75"; + public const string SIDS_ASINR = "76"; + public const string SIDS_ACOSR = "77"; + public const string SIDS_ATANR = "78"; + public const string SIDS_SING = "79"; + public const string SIDS_COSG = "80"; + public const string SIDS_TANG = "81"; + public const string SIDS_ASING = "82"; + public const string SIDS_ACOSG = "83"; + public const string SIDS_ATANG = "84"; + public const string SIDS_ASINH = "85"; + public const string SIDS_ACOSH = "86"; + public const string SIDS_ATANH = "87"; + public const string SIDS_POWE = "88"; + public const string SIDS_POWTEN2 = "89"; + public const string SIDS_SQRT2 = "90"; + public const string SIDS_SQR = "91"; + public const string SIDS_CUBE = "92"; + public const string SIDS_CUBERT = "93"; + public const string SIDS_FACT = "94"; + public const string SIDS_RECIPROC = "95"; + public const string SIDS_DEGREES = "96"; + public const string SIDS_NEGATE = "97"; + public const string SIDS_RSH2 = "98"; + public const string SIDS_DIVIDEBYZERO = "99"; + public const string SIDS_DOMAIN = "100"; + public const string SIDS_UNDEFINED = "101"; + public const string SIDS_POS_INFINITY = "102"; + public const string SIDS_NEG_INFINITY = "103"; + public const string SIDS_ABORTED = "104"; + public const string SIDS_NOMEM = "105"; + public const string SIDS_TOOMANY = "106"; + public const string SIDS_OVERFLOW = "107"; + public const string SIDS_NORESULT = "108"; + public const string SIDS_INSUFFICIENT_DATA = "109"; + // 110 is skipped by CSTRINGSENGMAX + public const string SIDS_ERR_UNK_CH = "111"; + public const string SIDS_ERR_UNK_FN = "112"; + public const string SIDS_ERR_UNEX_NUM = "113"; + public const string SIDS_ERR_UNEX_CH = "114"; + public const string SIDS_ERR_UNEX_SZ = "115"; + public const string SIDS_ERR_MISMATCH_CLOSE = "116"; + public const string SIDS_ERR_UNEX_END = "117"; + public const string SIDS_ERR_SG_INV_ERROR = "118"; + public const string SIDS_ERR_INPUT_OVERFLOW = "119"; + public const string SIDS_ERR_OUTPUT_OVERFLOW = "120"; + + // Include the resource key ID from above into this vector to load it into memory for the engine to use + public static readonly string[] g_sids = { SIDS_PLUS_MINUS, + SIDS_C, + SIDS_CE, + SIDS_BACKSPACE, + SIDS_DECIMAL_SEPARATOR, + SIDS_EMPTY_STRING, + SIDS_AND, + SIDS_OR, + SIDS_XOR, + SIDS_LSH, + SIDS_RSH, + SIDS_DIVIDE, + SIDS_MULTIPLY, + SIDS_PLUS, + SIDS_MINUS, + SIDS_MOD, + SIDS_YROOT, + SIDS_POW_HAT, + SIDS_INT, + SIDS_ROL, + SIDS_ROR, + SIDS_NOT, + SIDS_SIN, + SIDS_COS, + SIDS_TAN, + SIDS_SINH, + SIDS_COSH, + SIDS_TANH, + SIDS_LN, + SIDS_LOG, + SIDS_SQRT, + SIDS_XPOW2, + SIDS_XPOW3, + SIDS_NFACTORIAL, + SIDS_RECIPROCAL, + SIDS_DMS, + SIDS_CUBEROOT, + SIDS_POWTEN, + SIDS_PERCENT, + SIDS_SCIENTIFIC_NOTATION, + SIDS_PI, + SIDS_EQUAL, + SIDS_MC, + SIDS_MR, + SIDS_MS, + SIDS_MPLUS, + SIDS_MMINUS, + SIDS_EXP, + SIDS_OPEN_PAREN, + SIDS_CLOSE_PAREN, + SIDS_0, + SIDS_1, + SIDS_2, + SIDS_3, + SIDS_4, + SIDS_5, + SIDS_6, + SIDS_7, + SIDS_8, + SIDS_9, + SIDS_A, + SIDS_B, + SIDS_C, + SIDS_D, + SIDS_E, + SIDS_F, + SIDS_FRAC, + SIDS_SIND, + SIDS_COSD, + SIDS_TAND, + SIDS_ASIND, + SIDS_ACOSD, + SIDS_ATAND, + SIDS_SINR, + SIDS_COSR, + SIDS_TANR, + SIDS_ASINR, + SIDS_ACOSR, + SIDS_ATANR, + SIDS_SING, + SIDS_COSG, + SIDS_TANG, + SIDS_ASING, + SIDS_ACOSG, + SIDS_ATANG, + SIDS_ASINH, + SIDS_ACOSH, + SIDS_ATANH, + SIDS_POWE, + SIDS_POWTEN2, + SIDS_SQRT2, + SIDS_SQR, + SIDS_CUBE, + SIDS_CUBERT, + SIDS_FACT, + SIDS_RECIPROC, + SIDS_DEGREES, + SIDS_NEGATE, + SIDS_RSH, + SIDS_DIVIDEBYZERO, + SIDS_DOMAIN, + SIDS_UNDEFINED, + SIDS_POS_INFINITY, + SIDS_NEG_INFINITY, + SIDS_ABORTED, + SIDS_NOMEM, + SIDS_TOOMANY, + SIDS_OVERFLOW, + SIDS_NORESULT, + SIDS_INSUFFICIENT_DATA, + SIDS_ERR_UNK_CH, + SIDS_ERR_UNK_FN, + SIDS_ERR_UNEX_NUM, + SIDS_ERR_UNEX_CH, + SIDS_ERR_UNEX_SZ, + SIDS_ERR_MISMATCH_CLOSE, + SIDS_ERR_UNEX_END, + SIDS_ERR_SG_INV_ERROR, + SIDS_ERR_INPUT_OVERFLOW, + SIDS_ERR_OUTPUT_OVERFLOW }; + + } +} diff --git a/src/Calculator.Shared/CalcManager/ExpressionCommandInterface.cs b/src/Calculator.Shared/CalcManager/ExpressionCommandInterface.cs new file mode 100644 index 00000000..e211b522 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/ExpressionCommandInterface.cs @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp; +using System; + +namespace CalculationManager +{ + public interface ISerializeCommandVisitor + { + void Visit(COpndCommand opndCmd); + void Visit(CUnaryCommand unaryCmd); + void Visit(CBinaryCommand binaryCmd); + void Visit(CParentheses paraCmd); + }; + + + public interface IExpressionCommand + { + CalculationManager.CommandType GetCommandType(); + void Accept(ISerializeCommandVisitor commandVisitor); + } + + public interface IOperatorCommand : IExpressionCommand + { + void SetCommand(int command); + } + + public interface IUnaryCommand : IOperatorCommand + { + CalculatorList GetCommands(); + void SetCommands(int command1, int command2); + } + + public interface IBinaryCommand : IOperatorCommand + { + new void SetCommand(int command); + int GetCommand(); + } + + public interface IOpndCommand : IExpressionCommand + { + CalculatorList GetCommands(); + void AppendCommand(int command); + void ToggleSign(); + void RemoveFromEnd(); + bool IsNegative(); + bool IsSciFmt(); + bool IsDecimalPresent(); + string GetToken(char decimalSymbol); + void SetCommands(CalculatorList commands); + } + + public interface IParenthesisCommand : IExpressionCommand + { + int GetCommand(); + } + + + + + public class CParentheses : IParenthesisCommand + { + public CParentheses(int command) => throw new NotImplementedException(); + public int GetCommand() => throw new NotImplementedException(); + public CalculationManager.CommandType GetCommandType() => throw new NotImplementedException(); + public void Accept(ISerializeCommandVisitor commandVisitor) => throw new NotImplementedException(); + } + + public class CUnaryCommand : IUnaryCommand + { + public CUnaryCommand(int command) => throw new NotImplementedException(); + public CUnaryCommand(int command1, int command2) => throw new NotImplementedException(); + public CalculatorList GetCommands() => throw new NotImplementedException(); + public CalculationManager.CommandType GetCommandType() => throw new NotImplementedException(); + public void SetCommand(int command) => throw new NotImplementedException(); + public void SetCommands(int command1, int command2) => throw new NotImplementedException(); + public void Accept(ISerializeCommandVisitor commandVisitor) => throw new NotImplementedException(); + } + + public class CBinaryCommand : IBinaryCommand + { + public CBinaryCommand(int command) => throw new NotImplementedException(); + public void SetCommand(int command) => throw new NotImplementedException(); + public int GetCommand() => throw new NotImplementedException(); + public CommandType GetCommandType() => throw new NotImplementedException(); + public void Accept(ISerializeCommandVisitor commandVisitor) => throw new NotImplementedException(); + } + + public class COpndCommand : IOpndCommand + { + public COpndCommand(CalculatorList commands, bool fNegative, bool fDecimal, bool fSciFmt) => throw new NotImplementedException(); + // public void Initialize(CalcEngine.Rational rat) => throw new NotImplementedException(); + + public CalculatorList GetCommands() => throw new NotImplementedException(); + public void SetCommands(CalculatorList commands) => throw new NotImplementedException(); + public void AppendCommand(int command) => throw new NotImplementedException(); + public void ToggleSign() => throw new NotImplementedException(); + public void RemoveFromEnd() => throw new NotImplementedException(); + public bool IsNegative() => throw new NotImplementedException(); + public bool IsSciFmt() => throw new NotImplementedException(); + public bool IsDecimalPresent() => throw new NotImplementedException(); + public string GetToken(char decimalSymbol) => throw new NotImplementedException(); + public CalculationManager.CommandType GetCommandType() => throw new NotImplementedException(); + public void Accept(ISerializeCommandVisitor commandVisitor) => throw new NotImplementedException(); + public string GetString(uint radix, int precision) => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/CalcManager/RadixType.cs b/src/Calculator.Shared/CalcManager/RadixType.cs new file mode 100644 index 00000000..1c049df1 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/RadixType.cs @@ -0,0 +1,10 @@ +namespace CalculationManager +{ + public enum RADIX_TYPE : int + { + HEX_RADIX, + DEC_RADIX, + OCT_RADIX, + BIN_RADIX + }; +} \ No newline at end of file diff --git a/src/Calculator.Shared/CalcManager/RatPak.cs b/src/Calculator.Shared/CalcManager/RatPak.cs new file mode 100644 index 00000000..ad20fb19 --- /dev/null +++ b/src/Calculator.Shared/CalcManager/RatPak.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculationManager +{ + public enum NUMOBJ_FMT + { + FMT_FLOAT, // returns floating point, or exponential if number is too big + FMT_SCIENTIFIC, // always returns scientific notation + FMT_ENGINEERING // always returns engineering notation such that exponent is a multiple of 3 + } + + public enum ANGLE_TYPE + { + ANGLE_DEG, // Calculate trig using 360 degrees per revolution + ANGLE_RAD, // Calculate trig using 2 pi radians per revolution + ANGLE_GRAD // Calculate trig using 400 gradients per revolution + } +} diff --git a/src/Calculator.Shared/CalcManager/UnitConversionManager.cs b/src/Calculator.Shared/CalcManager/UnitConversionManager.cs new file mode 100644 index 00000000..d193f26e --- /dev/null +++ b/src/Calculator.Shared/CalcManager/UnitConversionManager.cs @@ -0,0 +1,58 @@ + + +namespace UnitConversionManager +{ + public struct Unit + { + public Unit(int id, string name, string abbreviation, bool isConversionSource, bool isConversionTarget, bool isWhimsical) + { + this.id = id; + this.name = name; + this.accessibleName = name; + this.abbreviation = abbreviation; + this.isConversionSource = isConversionSource; + this.isConversionTarget = isConversionTarget; + this.isWhimsical = isWhimsical; + } + + public Unit( + int id, + string currencyName, + string countryName, + string abbreviation, + bool isRtlLanguage, + bool isConversionSource, + bool isConversionTarget) + { + this.id = id; + this.abbreviation = abbreviation; + this.isConversionSource = isConversionSource; + this.isConversionTarget = isConversionTarget; + this.isWhimsical = false; + + string nameValue1 = isRtlLanguage ? currencyName : countryName; + string nameValue2 = isRtlLanguage ? countryName : currencyName; + + name = nameValue1 + " - " + nameValue2; + accessibleName = nameValue1 + " " + nameValue2; + } + + public readonly int id; + public readonly string name; + public readonly string accessibleName; + public readonly string abbreviation; + public readonly bool isConversionSource; + public readonly bool isConversionTarget; + public readonly bool isWhimsical; + + // bool operator !=(Unit that) const + // { + // return that.id != id; + // } + + //bool operator ==(Unit that) const + // { + // return that.id == id; + // } + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/Calculator.Shared.projitems b/src/Calculator.Shared/Calculator.Shared.projitems new file mode 100644 index 00000000..6dd46e12 --- /dev/null +++ b/src/Calculator.Shared/Calculator.Shared.projitems @@ -0,0 +1,379 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 6279c845-92f8-4333-ab99-3d213163593c + + + CalculatorApp + + + + Designer + MSBuild:Compile + + + + + App.xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MainPage.xaml + + + AboutFlyout.xaml + + + Calculator.xaml + + + CalculatorProgrammerBitFlipPanel.xaml + + + CalculatorProgrammerDisplayPanel.xaml + + + CalculatorProgrammerOperators.xaml + + + CalculatorProgrammerRadixOperators.xaml + + + CalculatorScientificAngleButtons.xaml + + + CalculatorScientificOperators.xaml + + + CalculatorStandardOperators.xaml + + + DateCalculator.xaml + + + HistoryList.xaml + + + Memory.xaml + + + MemoryListItem.xaml + + + NumberPad.xaml + + + OperatorsPanel.xaml + + + + SupplementaryResults.xaml + + + TitleBar.xaml + + + UnitConverter.xaml + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Calculator.Shared/Calculator.Shared.shproj b/src/Calculator.Shared/Calculator.Shared.shproj new file mode 100644 index 00000000..4df3bc47 --- /dev/null +++ b/src/Calculator.Shared/Calculator.Shared.shproj @@ -0,0 +1,13 @@ + + + + 6279c845-92f8-4333-ab99-3d213163593c + 14.0 + + + + + + + + diff --git a/src/Calculator.Shared/Common/AlwaysSelectedCollectionView.cs b/src/Calculator.Shared/Common/AlwaysSelectedCollectionView.cs new file mode 100644 index 00000000..a76eb105 --- /dev/null +++ b/src/Calculator.Shared/Common/AlwaysSelectedCollectionView.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.Foundation; +using Windows.UI.Xaml.Data; + +namespace WindowsCalculator.Shared.Common +{ + class AlwaysSelectedCollectionView + { + } +} diff --git a/src/Calculator.Shared/Common/AppLifecycleLogger.cs b/src/Calculator.Shared/Common/AppLifecycleLogger.cs new file mode 100644 index 00000000..32df0194 --- /dev/null +++ b/src/Calculator.Shared/Common/AppLifecycleLogger.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WindowsCalculator.Shared.Common +{ + class AppLifecycleLogger + { + } +} diff --git a/src/Calculator.Shared/Common/AppResourceProvider.cs b/src/Calculator.Shared/Common/AppResourceProvider.cs new file mode 100644 index 00000000..b8538ac8 --- /dev/null +++ b/src/Calculator.Shared/Common/AppResourceProvider.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Windows.ApplicationModel.Resources; + +namespace CalculatorApp +{ + public class AppResourceProvider + { + Windows.ApplicationModel.Resources.ResourceLoader m_stringResLoader; + Windows.ApplicationModel.Resources.ResourceLoader m_cEnginestringResLoader; + private static AppResourceProvider s_instance; + + public AppResourceProvider() + { + m_stringResLoader = ResourceLoader.GetForViewIndependentUse(); + m_cEnginestringResLoader = ResourceLoader.GetForViewIndependentUse("CEnginestrings"); + } + + public static AppResourceProvider GetInstance() + { + if(s_instance == null) + { + s_instance = new AppResourceProvider(); + } + + return s_instance; + } + + public string GetResourceString(string key) + { + return m_stringResLoader.GetString(key); + } + + public string GetCEngineString(string key) + { + return m_cEnginestringResLoader.GetString(key); + } + } +} diff --git a/src/Calculator.Shared/Common/Automation/NarratorAnnouncement.cs b/src/Calculator.Shared/Common/Automation/NarratorAnnouncement.cs new file mode 100644 index 00000000..cbc883aa --- /dev/null +++ b/src/Calculator.Shared/Common/Automation/NarratorAnnouncement.cs @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace CalculatorApp.Common.Automation +{ + // These enum types are copied from the types available in + // Windows.UI.Xaml.Automation.Peers in the RS3 SDK. + // When this app switches to min version RS3, these custom + // enums should be removed and the Windows types should be used + // instead. + // TODO - MSFT 12735088 + public enum AutomationNotificationKind + { + ItemAdded = 0, + ItemRemoved = 1, + ActionCompleted = 2, + ActionAborted = 3, + Other = 4 + }; + + public enum AutomationNotificationProcessing + { + ImportantAll = 0, + ImportantMostRecent = 1, + All = 2, + MostRecent = 3, + CurrentThenMostRecent = 4 + }; + + public class NarratorAnnouncement + { + private string m_announcement; + private string m_activityId; + private AutomationNotificationKind m_kind; + private AutomationNotificationProcessing m_processing; + + public NarratorAnnouncement( + string announcement, + string activityId, + AutomationNotificationKind kind, + AutomationNotificationProcessing processing) + { + m_announcement = announcement; + m_activityId = activityId; + m_kind = kind; + m_processing = processing; + } + + public string Announcement => m_announcement; + + public string ActivityId => m_activityId; + + public AutomationNotificationKind Kind => m_kind; + + public AutomationNotificationProcessing Processing => m_processing; + + public bool IsValid(NarratorAnnouncement announcement) + => announcement != null && announcement.Announcement != null && !string.IsNullOrEmpty(announcement.Announcement); + }; + + // CalculatorAnnouncement is intended to contain only static methods + // that return announcements made for the Calculator app. + public class CalculatorAnnouncement + { + const string DisplayUpdated = "DisplayUpdated"; + const string MaxDigitsReached = "MaxDigitsReached"; + const string MemoryCleared = "MemoryCleared"; + const string MemoryItemChanged = "MemorySlotChanged"; + const string MemoryItemAdded = "MemorySlotAdded"; + const string HistoryCleared = "HistoryCleared"; + const string CategoryNameChanged = "CategoryNameChanged"; + const string UpdateCurrencyRates = "UpdateCurrencyRates"; + const string DisplayCopied = "DisplayCopied"; + const string OpenParenthesisCountChanged = "OpenParenthesisCountChanged"; + const string NoParenthesisAdded = "NoParenthesisAdded"; + + public static NarratorAnnouncement GetDisplayUpdatedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, DisplayUpdated, AutomationNotificationKind.Other, AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetMaxDigitsReachedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, MaxDigitsReached, AutomationNotificationKind.Other, AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetMemoryClearedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, MemoryCleared, AutomationNotificationKind.ItemRemoved, AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetMemoryItemChangedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, MemoryItemChanged, AutomationNotificationKind.ActionCompleted, AutomationNotificationProcessing.MostRecent); + } + + public static NarratorAnnouncement GetMemoryItemAddedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, MemoryItemAdded, AutomationNotificationKind.ItemAdded, AutomationNotificationProcessing.MostRecent); + } + + public static NarratorAnnouncement GetHistoryClearedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, HistoryCleared, AutomationNotificationKind.ItemRemoved, AutomationNotificationProcessing.MostRecent); + } + + public static NarratorAnnouncement GetCategoryNameChangedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, + CategoryNameChanged, + AutomationNotificationKind.ActionCompleted, + AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetUpdateCurrencyRatesAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, + UpdateCurrencyRates, + AutomationNotificationKind.ActionCompleted, + AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetDisplayCopiedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, DisplayCopied, AutomationNotificationKind.ActionCompleted, AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetOpenParenthesisCountChangedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, + OpenParenthesisCountChanged, + AutomationNotificationKind.ActionCompleted, + AutomationNotificationProcessing.ImportantMostRecent); + } + + public static NarratorAnnouncement GetNoRightParenthesisAddedAnnouncement(string announcement) + { + return new NarratorAnnouncement( + announcement, + NoParenthesisAdded, + AutomationNotificationKind.ActionCompleted, + AutomationNotificationProcessing.ImportantMostRecent); + } + } +} diff --git a/src/Calculator.Shared/Common/BindableBase.cs b/src/Calculator.Shared/Common/BindableBase.cs new file mode 100644 index 00000000..2601792f --- /dev/null +++ b/src/Calculator.Shared/Common/BindableBase.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WindowsCalculator.Shared.Common +{ + class BindableBase + { + } +} diff --git a/src/Calculator.Shared/Common/CalculatorButtonPressedEventArgs.cs b/src/Calculator.Shared/Common/CalculatorButtonPressedEventArgs.cs new file mode 100644 index 00000000..304916e2 --- /dev/null +++ b/src/Calculator.Shared/Common/CalculatorButtonPressedEventArgs.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace CalculatorApp +{ + namespace Common + { + public sealed class CalculatorButtonPressedEventArgs + { + public string AuditoryFeedback { get; private set; } + public CalculatorApp.NumbersAndOperatorsEnum Operation { get; private set; } + + public CalculatorButtonPressedEventArgs(string feedback, CalculatorApp.NumbersAndOperatorsEnum operation) + { + AuditoryFeedback = feedback; + Operation = operation; + } + + static public NumbersAndOperatorsEnum GetOperationFromCommandParameter(object commandParameter) + { + if (commandParameter is CalculatorButtonPressedEventArgs eventArgs) + { + return eventArgs.Operation; + } + else + { + return (NumbersAndOperatorsEnum)commandParameter; + } + } + + static public string GetAuditoryFeedbackFromCommandParameter(object commandParameter) + { + if (commandParameter is CalculatorButtonPressedEventArgs eventArgs) + { + return eventArgs.AuditoryFeedback; + } + else + { + return null; + } + } + }; + } +} diff --git a/src/Calculator.Shared/Common/CalculatorButtonUser.cs b/src/Calculator.Shared/Common/CalculatorButtonUser.cs new file mode 100644 index 00000000..39b422a1 --- /dev/null +++ b/src/Calculator.Shared/Common/CalculatorButtonUser.cs @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +namespace CalculatorApp +{ + using CM = CalculationManager; + + public enum NumbersAndOperatorsEnum + { + Zero = (int)CM.Command.Command0, + One = (int)CM.Command.Command1, + Two = (int)CM.Command.Command2, + Three = (int)CM.Command.Command3, + Four = (int)CM.Command.Command4, + Five = (int)CM.Command.Command5, + Six = (int)CM.Command.Command6, + Seven = (int)CM.Command.Command7, + Eight = (int)CM.Command.Command8, + Nine = (int)CM.Command.Command9, + Add = (int)CM.Command.CommandADD, + Subtract = (int)CM.Command.CommandSUB, + Multiply = (int)CM.Command.CommandMUL, + Divide = (int)CM.Command.CommandDIV, + Invert = (int)CM.Command.CommandREC, + Equals = (int)CM.Command.CommandEQU, + Decimal = (int)CM.Command.CommandPNT, + Sqrt = (int)CM.Command.CommandSQRT, + Percent = (int)CM.Command.CommandPERCENT, + Negate = (int)CM.Command.CommandSIGN, + Backspace = (int)CM.Command.CommandBACK, + ClearEntry = (int)CM.Command.CommandCENTR, + Clear = (int)CM.Command.CommandCLEAR, + Degree = (int)CM.Command.CommandDEG, + Radians = (int)CM.Command.CommandRAD, + Grads = (int)CM.Command.CommandGRAD, + Degrees = (int)CM.Command.CommandDegrees, + OpenParenthesis = (int)CM.Command.CommandOPENP, + CloseParenthesis = (int)CM.Command.CommandCLOSEP, + Pi = (int)CM.Command.CommandPI, + Sin = (int)CM.Command.CommandSIN, + Cos = (int)CM.Command.CommandCOS, + Tan = (int)CM.Command.CommandTAN, + Factorial = (int)CM.Command.CommandFAC, + XPower2 = (int)CM.Command.CommandSQR, + Mod = (int)CM.Command.CommandMOD, + FToE = (int)CM.Command.CommandFE, + LogBaseE = (int)CM.Command.CommandLN, + InvSin = (int)CM.Command.CommandASIN, + InvCos = (int)CM.Command.CommandACOS, + InvTan = (int)CM.Command.CommandATAN, + LogBase10 = (int)CM.Command.CommandLOG, + XPowerY = (int)CM.Command.CommandPWR, + YRootX = (int)CM.Command.CommandROOT, + TenPowerX = (int)CM.Command.CommandPOW10, + EPowerX = (int)CM.Command.CommandPOWE, + Exp = (int)CM.Command.CommandEXP, + IsScientificMode = (int)CM.Command.ModeScientific, + 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, + Or = (int)CM.Command.CommandOR, + Lsh = (int)CM.Command.CommandLSHF, + Rsh = (int)CM.Command.CommandRSHF, + Xor = (int)CM.Command.CommandXor, + Not = (int)CM.Command.CommandNot, + A = (int)CM.Command.CommandA, + B = (int)CM.Command.CommandB, + C = (int)CM.Command.CommandC, + D = (int)CM.Command.CommandD, + E = (int)CM.Command.CommandE, + F = (int)CM.Command.CommandF, + Memory, // This is the memory button. Doesn't have a direct mapping to the CalcEngine. + Sinh = (int)CM.Command.CommandSINH, + Cosh = (int)CM.Command.CommandCOSH, + Tanh = (int)CM.Command.CommandTANH, + 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, + + BINSTART = (int)CM.Command.CommandBINEDITSTART, + BINPOS0 = (int)CM.Command.CommandBINPOS0, + BINPOS1 = (int)CM.Command.CommandBINPOS1, + BINPOS2 = (int)CM.Command.CommandBINPOS2, + BINPOS3 = (int)CM.Command.CommandBINPOS3, + BINPOS4 = (int)CM.Command.CommandBINPOS4, + BINPOS5 = (int)CM.Command.CommandBINPOS5, + BINPOS6 = (int)CM.Command.CommandBINPOS6, + BINPOS7 = (int)CM.Command.CommandBINPOS7, + BINPOS8 = (int)CM.Command.CommandBINPOS8, + BINPOS9 = (int)CM.Command.CommandBINPOS9, + BINPOS10 = (int)CM.Command.CommandBINPOS10, + BINPOS11 = (int)CM.Command.CommandBINPOS11, + BINPOS12 = (int)CM.Command.CommandBINPOS12, + BINPOS13 = (int)CM.Command.CommandBINPOS13, + BINPOS14 = (int)CM.Command.CommandBINPOS14, + BINPOS15 = (int)CM.Command.CommandBINPOS15, + BINPOS16 = (int)CM.Command.CommandBINPOS16, + BINPOS17 = (int)CM.Command.CommandBINPOS17, + BINPOS18 = (int)CM.Command.CommandBINPOS18, + BINPOS19 = (int)CM.Command.CommandBINPOS19, + BINPOS20 = (int)CM.Command.CommandBINPOS20, + BINPOS21 = (int)CM.Command.CommandBINPOS21, + BINPOS22 = (int)CM.Command.CommandBINPOS22, + BINPOS23 = (int)CM.Command.CommandBINPOS23, + BINPOS24 = (int)CM.Command.CommandBINPOS24, + BINPOS25 = (int)CM.Command.CommandBINPOS25, + BINPOS26 = (int)CM.Command.CommandBINPOS26, + BINPOS27 = (int)CM.Command.CommandBINPOS27, + BINPOS28 = (int)CM.Command.CommandBINPOS28, + BINPOS29 = (int)CM.Command.CommandBINPOS29, + BINPOS30 = (int)CM.Command.CommandBINPOS30, + BINPOS31 = (int)CM.Command.CommandBINPOS31, + BINPOS32 = (int)CM.Command.CommandBINPOS32, + BINPOS33 = (int)CM.Command.CommandBINPOS33, + BINPOS34 = (int)CM.Command.CommandBINPOS34, + BINPOS35 = (int)CM.Command.CommandBINPOS35, + BINPOS36 = (int)CM.Command.CommandBINPOS36, + BINPOS37 = (int)CM.Command.CommandBINPOS37, + BINPOS38 = (int)CM.Command.CommandBINPOS38, + BINPOS39 = (int)CM.Command.CommandBINPOS39, + BINPOS40 = (int)CM.Command.CommandBINPOS40, + BINPOS41 = (int)CM.Command.CommandBINPOS41, + BINPOS42 = (int)CM.Command.CommandBINPOS42, + BINPOS43 = (int)CM.Command.CommandBINPOS43, + BINPOS44 = (int)CM.Command.CommandBINPOS44, + BINPOS45 = (int)CM.Command.CommandBINPOS45, + BINPOS46 = (int)CM.Command.CommandBINPOS46, + BINPOS47 = (int)CM.Command.CommandBINPOS47, + BINPOS48 = (int)CM.Command.CommandBINPOS48, + BINPOS49 = (int)CM.Command.CommandBINPOS49, + BINPOS50 = (int)CM.Command.CommandBINPOS50, + BINPOS51 = (int)CM.Command.CommandBINPOS51, + BINPOS52 = (int)CM.Command.CommandBINPOS52, + BINPOS53 = (int)CM.Command.CommandBINPOS53, + BINPOS54 = (int)CM.Command.CommandBINPOS54, + BINPOS55 = (int)CM.Command.CommandBINPOS55, + BINPOS56 = (int)CM.Command.CommandBINPOS56, + BINPOS57 = (int)CM.Command.CommandBINPOS57, + BINPOS58 = (int)CM.Command.CommandBINPOS58, + BINPOS59 = (int)CM.Command.CommandBINPOS59, + BINPOS60 = (int)CM.Command.CommandBINPOS60, + 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 + } + + // This contains list of functions whose usage we are tracelogging + public enum FunctionLogEnum + { + Invert = (int)CM.Command.CommandREC, + Sqrt = (int)CM.Command.CommandSQRT, + Percent = (int)CM.Command.CommandPERCENT, + Negate = (int)CM.Command.CommandSIGN, + Degrees = (int)CM.Command.CommandDegrees, + Pi = (int)CM.Command.CommandPI, + Sin = (int)CM.Command.CommandSIN, + Cos = (int)CM.Command.CommandCOS, + Tan = (int)CM.Command.CommandTAN, + Factorial = (int)CM.Command.CommandFAC, + XPower2 = (int)CM.Command.CommandSQR, + Mod = (int)CM.Command.CommandMOD, + FToE = (int)CM.Command.CommandFE, + LogBaseE = (int)CM.Command.CommandLN, + InvSin = (int)CM.Command.CommandASIN, + InvCos = (int)CM.Command.CommandACOS, + InvTan = (int)CM.Command.CommandATAN, + LogBase10 = (int)CM.Command.CommandLOG, + XPowerY = (int)CM.Command.CommandPWR, + YRootX = (int)CM.Command.CommandROOT, + TenPowerX = (int)CM.Command.CommandPOW10, + EPowerX = (int)CM.Command.CommandPOWE, + Exp = (int)CM.Command.CommandEXP, + 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, + Or = (int)CM.Command.CommandOR, + Lsh = (int)CM.Command.CommandLSHF, + Rsh = (int)CM.Command.CommandRSHF, + Xor = (int)CM.Command.CommandXor, + Not = (int)CM.Command.CommandNot, + Sinh = (int)CM.Command.CommandSINH, + Cosh = (int)CM.Command.CommandCOSH, + Tanh = (int)CM.Command.CommandTANH, + InvSinh = (int)CM.Command.CommandASINH, + InvCosh = (int)CM.Command.CommandACOSH, + InvTanh = (int)CM.Command.CommandATANH, + Cube = (int)CM.Command.CommandCUB, + DMS = (int)CM.Command.CommandDMS, + } +} diff --git a/src/Calculator.Shared/Common/CalculatorDisplay.cs b/src/Calculator.Shared/Common/CalculatorDisplay.cs new file mode 100644 index 00000000..43f3eb71 --- /dev/null +++ b/src/Calculator.Shared/Common/CalculatorDisplay.cs @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculationManager; +using System; +using System.Collections.Generic; + +namespace CalculatorApp +{ + // Callback interface to be implemented by the CalculatorManager + public class CalculatorDisplay : ICalcDisplay + { + private WeakReference m_callbackReference; + private WeakReference m_historyCallbackReference; + + + public CalculatorDisplay() + { + } + + public void SetCallback(WeakReference callbackReference) + { + m_callbackReference = callbackReference; + } + + public void SetHistoryCallback(WeakReference callbackReference) + { + m_historyCallbackReference = callbackReference; + } + + public void SetPrimaryDisplay(string displayStringValue, bool isError) + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.SetPrimaryDisplay(displayStringValue, isError); + } + } + } + + public void SetParenthesisNumber(int parenthesisCount) + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.SetParenthesisCount(parenthesisCount); + } + } + } + + public void OnNoRightParenAdded() + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.OnNoRightParenAdded(); + } + } + } + + public void SetIsInError(bool isError) + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.IsInError = isError; + } + } + } + + public void SetExpressionDisplay( + CalculatorList<(string, int)> tokens, + CalculatorList commands) + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.SetExpressionDisplay(tokens, commands); + } + } + } + + public void SetMemorizedNumbers(List newMemorizedNumbers) + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.SetMemorizedNumbers(newMemorizedNumbers); + } + } + } + + public void OnHistoryItemAdded(int addedItemIndex) + { + if (m_historyCallbackReference != null) + { + if (m_callbackReference.Target is ViewModel.HistoryViewModel historyVM) + { + historyVM.OnHistoryItemAdded(addedItemIndex); + } + } + } + + public void MaxDigitsReached() + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.OnMaxDigitsReached(); + } + } + } + + public void BinaryOperatorReceived() + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.OnBinaryOperatorReceived(); + } + } + } + + public void MemoryItemChanged(int indexOfMemory) + { + if (m_callbackReference != null) + { + if (m_callbackReference.Target is ViewModel.StandardCalculatorViewModel calcVM) + { + calcVM.OnMemoryItemChanged(indexOfMemory); + } + } + } + } +} diff --git a/src/Calculator.Shared/Common/CopyPasteManager.cs b/src/Calculator.Shared/Common/CopyPasteManager.cs new file mode 100644 index 00000000..93d9e62b --- /dev/null +++ b/src/Calculator.Shared/Common/CopyPasteManager.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using CalculatorApp.Common; + +namespace CalculatorApp +{ + public class CopyPasteManager + { + public const string PasteErrorString = "NoOp"; + + public const int QwordType = 1; + public const int DwordType = 2; + public const int WordType = 3; + public const int ByteType = 4; + public const int HexBase = 5; + public const int DecBase = 6; + public const int OctBase = 7; + public const int BinBase = 8; + + internal static bool HasStringToPaste() => throw new NotImplementedException(); + internal static Task GetStringToPaste(ViewMode mode, CategoryGroupType categoryGroupType, int numberBase, int bitLengthType) => throw new NotImplementedException(); + internal static void CopyToClipboard(string v) => throw new NotImplementedException(); + } +} diff --git a/src/Calculator.Shared/Common/DelegateCommand.cs b/src/Calculator.Shared/Common/DelegateCommand.cs new file mode 100644 index 00000000..ae8b0ca0 --- /dev/null +++ b/src/Calculator.Shared/Common/DelegateCommand.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Windows.Input; + +namespace CalculatorApp +{ + namespace Common + { + public delegate void CommandHandlerFunc (object param); + + public class DelegateCommand : ICommand + { + public DelegateCommand(CommandHandlerFunc func) + { + m_function = func; + } + + // the ICommand methods will only be available if the ICommand interface is requested via a dynamic_cast + // The ICommand interface is meant to be consumed by Xaml and not by the app, this is a defensive measure against + // code in the app calling Execute. + public void Execute(object parameter) => m_function(parameter); + + public bool CanExecute(object parameter) => true; + + CommandHandlerFunc m_function; + + public event EventHandler CanExecuteChanged; + } + } +} diff --git a/src/Calculator.Shared/Common/DisplayExpressionToken.cs b/src/Calculator.Shared/Common/DisplayExpressionToken.cs new file mode 100644 index 00000000..fff0ef40 --- /dev/null +++ b/src/Calculator.Shared/Common/DisplayExpressionToken.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System.ComponentModel; + +namespace CalculatorApp.Common +{ + public enum TokenType + { + Operator, + Operand, + Separator + }; + + [Windows.UI.Xaml.Data.Bindable] + public sealed class DisplayExpressionToken : INotifyPropertyChanged + { + internal DisplayExpressionToken(string token, int tokenPosition, bool fEditable, TokenType type) + { + m_Token = token; + m_TokenPosition = tokenPosition; + m_IsTokenEditable = fEditable; + m_Type = type; + m_OriginalToken = token; + m_InEditMode = false; + } + + public event PropertyChangedEventHandler PropertyChanged; + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); + private string m_Token; + public string Token { get => m_Token; set { m_Token = value; RaisePropertyChanged("Token"); } } + + + private int m_TokenPosition; + public int TokenPosition { get => m_TokenPosition; set { m_TokenPosition = value; RaisePropertyChanged("TokenPosition"); } } + + + private bool m_IsTokenEditable; + public bool IsTokenEditable { get => m_IsTokenEditable; set { m_IsTokenEditable = value; RaisePropertyChanged("IsTokenEditable"); } } + + + private int m_CommandIndex; + public int CommandIndex { get => m_CommandIndex; set { m_CommandIndex = value; RaisePropertyChanged("CommandIndex"); } } + + + private string m_OriginalToken; + public string OriginalToken { get => m_OriginalToken; private set { m_OriginalToken = value; RaisePropertyChanged("OriginalToken"); } } + + bool IsTokenInEditMode + { + get + { + return m_InEditMode; + } + set + { + if (!value) + { + m_OriginalToken = m_Token; + } + m_InEditMode = value; + } + } + + private TokenType m_Type; + public TokenType Type { get => m_Type; set { m_Type = value; RaisePropertyChanged("Type"); } } + + bool m_InEditMode; + }; +} diff --git a/src/Calculator.Shared/Common/EngineResourceProvider.cs b/src/Calculator.Shared/Common/EngineResourceProvider.cs new file mode 100644 index 00000000..fe10a8c8 --- /dev/null +++ b/src/Calculator.Shared/Common/EngineResourceProvider.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp.Common; +using Windows.ApplicationModel.Resources; + +namespace CalculatorApp +{ + public interface IResourceProvider + { + // Should return a string from the resource table for strings used + // by the calculation engine. The strings that must be defined + // and the ids to define them with can be seen in EngineStrings.h + // with SIDS prefix. Additionally it must provide values for string + // ids "sDecimal", "sThousand" and "sGrouping". See + // https://technet.microsoft.com/en-us/library/cc782655(v=ws.10).aspx + // for what these values refer to. + string GetCEngineString(string id); + }; + + + public class EngineResourceProvider : IResourceProvider + { + public EngineResourceProvider() + { + m_resLoader = ResourceLoader.GetForViewIndependentUse("CEngineStrings"); + } + + public string GetCEngineString(string id) + { + var localizationSettings = LocalizationSettings.GetInstance(); + + if (id.CompareTo("sDecimal") == 0) + { + return localizationSettings.GetDecimalSeparatorStr(); + } + + if (id.CompareTo("sThousand") == 0) + { + return localizationSettings.GetNumberGroupingSeparatorStr(); + } + + if (id.CompareTo("sGrouping") == 0) + { + // The following groupings are the onces that CalcEngine supports. + // 0;0 0x000 - no grouping + // 3;0 0x003 - group every 3 digits + // 3;2;0 0x023 - group 1st 3 and then every 2 digits + // 4;0 0x004 - group every 4 digits + // 5;3;2;0 0x235 - group 5, then 3, then every 2 + string numberGroupingString = localizationSettings.GetNumberGroupingStr(); + return numberGroupingString; + } + + return m_resLoader.GetString(id); + } + + Windows.ApplicationModel.Resources.ResourceLoader m_resLoader; + }; +} diff --git a/src/Calculator.Shared/Common/LocalizationService.cs b/src/Calculator.Shared/Common/LocalizationService.cs new file mode 100644 index 00000000..49ebcd44 --- /dev/null +++ b/src/Calculator.Shared/Common/LocalizationService.cs @@ -0,0 +1,587 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using Windows.ApplicationModel.Resources.Core; +using Windows.Globalization; +using Windows.Globalization.DateTimeFormatting; +using Windows.Globalization.Fonts; +using Windows.Globalization.NumberFormatting; +using Windows.System.UserProfile; +using Windows.UI.Text; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Documents; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Common +{ + + public enum LanguageFontType + { + UIText, + UICaption, + }; + + public sealed class LocalizationService + { + static string DefaultCurrencyCode = "USD"; + + + + public static LanguageFontType GetFontType(DependencyObject obj) => (LanguageFontType)obj.GetValue(FontTypeProperty); + + public static void SetFontType(DependencyObject obj, LanguageFontType value) => obj.SetValue(FontTypeProperty, value); + + public static readonly DependencyProperty FontTypeProperty = + DependencyProperty.RegisterAttached("FontType", typeof(LanguageFontType), typeof(LocalizationService), new PropertyMetadata(LanguageFontType.UIText)); + + + public static double GetFontSize(DependencyObject obj) => (double)obj.GetValue(FontSizeProperty); + + public static void SetFontSize(DependencyObject obj, double value) => obj.SetValue(FontSizeProperty, value); + + public static readonly DependencyProperty FontSizeProperty = + DependencyProperty.RegisterAttached("FontSize", typeof(double), typeof(LocalizationService), new PropertyMetadata(0)); + + static LocalizationService s_singletonInstance; + + Windows.Globalization.Fonts.LanguageFontGroup m_fontGroup; + string m_language; + Windows.UI.Xaml.FlowDirection m_flowDirection; + bool m_overrideFontApiValues; + string m_fontFamilyOverride; + Windows.UI.Text.FontWeight m_fontWeightOverride; + double m_uiTextFontScaleFactorOverride; + double m_uiCaptionFontScaleFactorOverride; + + + // Resources for the engine use numbers as keys. It's inconvenient, but also difficult to + // change given that the engine heavily relies on perfect ordering of certain elements. + // The key for open parenthesis, '(', is "48". + static string s_openParenResourceKey = "48"; + + public static LocalizationService GetInstance() + { + if (s_singletonInstance == null) + { + if (s_singletonInstance == null) + { + s_singletonInstance = new LocalizationService(); + } + } + + return s_singletonInstance; + } + + LocalizationService() + { +#if HAS_UNO + m_language = "en-US"; + m_flowDirection = FlowDirection.LeftToRight; +#else + m_language = ApplicationLanguages.Languages[0]; + m_flowDirection = + ResourceContext.GetForCurrentView().QualifierValues["LayoutDirection"] != "LTR" ? FlowDirection.RightToLeft : FlowDirection.LeftToRight; +#endif + + var resourceLoader = AppResourceProvider.GetInstance(); + m_fontFamilyOverride = resourceLoader.GetResourceString("LocalizedFontFamilyOverride"); + + string reserved = "RESERVED_FOR_FONTLOC"; + + m_overrideFontApiValues = ((m_fontFamilyOverride != null) && (m_fontFamilyOverride != reserved)); + if (m_overrideFontApiValues) + { + string localizedUICaptionFontSizeFactorOverride = resourceLoader.GetResourceString("LocalizedUICaptionFontSizeFactorOverride"); + string localizedUITextFontSizeFactorOverride = resourceLoader.GetResourceString("LocalizedUITextFontSizeFactorOverride"); + string localizedFontWeightOverride = resourceLoader.GetResourceString("LocalizedFontWeightOverride"); + + // If any of the font overrides are modified then all of them need to be modified + Debug.Assert(localizedFontWeightOverride != reserved); + Debug.Assert(localizedUITextFontSizeFactorOverride != reserved); + Debug.Assert(localizedUICaptionFontSizeFactorOverride != reserved); + + m_fontWeightOverride = ParseFontWeight(localizedFontWeightOverride); + m_uiTextFontScaleFactorOverride = double.Parse(localizedUITextFontSizeFactorOverride); + m_uiCaptionFontScaleFactorOverride = double.Parse(localizedUICaptionFontSizeFactorOverride); + } + + m_fontGroup = new LanguageFontGroup(m_language); + } + + FontWeight ParseFontWeight(string fontWeight) + { + fontWeight = fontWeight.ToLower(); + + if (fontWeight == "black") + { + return FontWeights.Black; + } + else if (fontWeight == "bold") + { + return FontWeights.Bold; + } + else if (fontWeight == "extrablack") + { + return FontWeights.ExtraBlack; + } + else if (fontWeight == "extrabold") + { + return FontWeights.ExtraBold; + } + else if (fontWeight == "extralight") + { + return FontWeights.ExtraLight; + } + else if (fontWeight == "light") + { + return FontWeights.Light; + } + else if (fontWeight == "medium") + { + return FontWeights.Medium; + } + else if (fontWeight == "normal") + { + return FontWeights.Normal; + } + else if (fontWeight == "semibold") + { + return FontWeights.SemiBold; + } + else if (fontWeight == "semilight") + { + return FontWeights.SemiLight; + } + else if (fontWeight == "thin") + { + return FontWeights.Thin; + } + else + { + throw new ArgumentException("Invalid argument: fontWeight"); + } + } + + FlowDirection GetFlowDirection() + { + return m_flowDirection; + } + + public bool IsRtlLayout() + { + return m_flowDirection == FlowDirection.RightToLeft; + } + + string GetLanguage() + { + return m_language; + } + + bool GetOverrideFontApiValues() + { + return m_overrideFontApiValues; + } + + public FontFamily GetLanguageFontFamilyForType(LanguageFontType fontType) + { + if (m_overrideFontApiValues) + { + return new FontFamily(m_fontFamilyOverride); + } + else + { + return new FontFamily(GetLanguageFont(fontType).FontFamily); + } + } + + LanguageFont GetLanguageFont(LanguageFontType fontType) + { + Debug.Assert(!m_overrideFontApiValues); + Debug.Assert(m_fontGroup != null); + + switch (fontType) + { + case LanguageFontType.UIText: + return m_fontGroup.UITextFont; + case LanguageFontType.UICaption: + return m_fontGroup.UICaptionFont; + default: + throw new ArgumentException("fontType"); + } + } + + string GetFontFamilyOverride() + { + Debug.Assert(m_overrideFontApiValues); + return m_fontFamilyOverride; + } + + FontWeight GetFontWeightOverride() + { + Debug.Assert(m_overrideFontApiValues); + return m_fontWeightOverride; + } + + double GetFontScaleFactorOverride(LanguageFontType fontType) + { + Debug.Assert(m_overrideFontApiValues); + + switch (fontType) + { + case LanguageFontType.UIText: + return m_uiTextFontScaleFactorOverride; + case LanguageFontType.UICaption: + return m_uiCaptionFontScaleFactorOverride; + default: + throw new ArgumentException("Invalid argument: fontType"); + } + } + + void OnFontTypePropertyChanged(DependencyObject target, LanguageFontType oldValue, LanguageFontType newValue) + { + UpdateFontFamilyAndSize(target); + } + + void OnFontWeightPropertyChanged(DependencyObject target, FontWeight oldValue, FontWeight newValue) + { + UpdateFontFamilyAndSize(target); + } + + void OnFontSizePropertyChanged(DependencyObject target, double oldValue, double newValue) + { + UpdateFontFamilyAndSize(target); + } + + void UpdateFontFamilyAndSize(DependencyObject target) + { + FontFamily fontFamily; + FontWeight fontWeight = FontWeights.Normal; + bool fOverrideFontWeight = false; + double scaleFactor; + + var service = GetInstance(); + var fontType = GetFontType(target); + + if (service.GetOverrideFontApiValues()) + { + fontFamily = new FontFamily(service.GetFontFamilyOverride()); + scaleFactor = service.GetFontScaleFactorOverride(fontType) / 100.0; + fontWeight = service.GetFontWeightOverride(); + fOverrideFontWeight = true; + } + else + { + var languageFont = service.GetLanguageFont(fontType); + fontFamily = new FontFamily(languageFont.FontFamily); + scaleFactor = languageFont.ScaleFactor / 100.0; + } + + double sizeToUse = GetFontSize(target) * scaleFactor; + + var control = target as Control; + if (control != null) + { + control.FontFamily = fontFamily; + if (fOverrideFontWeight) + { + control.FontWeight = fontWeight; + } + if (sizeToUse != 0.0) + { + control.FontSize = sizeToUse; + } + else + { + control.ClearValue(Control.FontSizeProperty); + } + } + else + { + var textBlock = target as TextBlock; + if (textBlock != null) + { + textBlock.FontFamily = fontFamily; + if (fOverrideFontWeight) + { + textBlock.FontWeight = fontWeight; + } + if (sizeToUse != 0.0) + { + textBlock.FontSize = sizeToUse; + } + else + { + textBlock.ClearValue(TextBlock.FontSizeProperty); + } + } + else + { + RichTextBlock richTextBlock = (target as RichTextBlock); + if (richTextBlock != null) + { + richTextBlock.FontFamily = fontFamily; + if (fOverrideFontWeight) + { + richTextBlock.FontWeight = fontWeight; + } + if (sizeToUse != 0.0) + { + richTextBlock.FontSize = sizeToUse; + } + else + { + richTextBlock.ClearValue(RichTextBlock.FontSizeProperty); + } + } + else + { + TextElement textElement = (target as TextElement); + if (textElement != null) + { + textElement.FontFamily = fontFamily; + if (fOverrideFontWeight) + { + textElement.FontWeight = fontWeight; + } + if (sizeToUse != 0.0) + { + textElement.FontSize = sizeToUse; + } + else + { + textElement.ClearValue(TextElement.FontSizeProperty); + } + } + } + } + } + } + + // If successful, returns a formatter that respects the user's regional format settings, + // as configured by running intl.cpl. + public static DecimalFormatter GetRegionalSettingsAwareDecimalFormatter() + { + IEnumerable languageIdentifiers = GetLanguageIdentifiers(); + if (languageIdentifiers != null) + { + return new DecimalFormatter(languageIdentifiers, GlobalizationPreferences.HomeGeographicRegion); + } + + return new DecimalFormatter(); + } + + // If successful, returns a formatter that respects the user's regional format settings, + // as configured by running intl.cpl. + // + // This helper function creates a DateTimeFormatter with a TwentyFour hour clock + DateTimeFormatter GetRegionalSettingsAwareDateTimeFormatter( string format) + { + IEnumerable languageIdentifiers = GetLanguageIdentifiers(); + if (languageIdentifiers == null) + { + languageIdentifiers = ApplicationLanguages.Languages; + } + + return new DateTimeFormatter(format, languageIdentifiers); + } + + // If successful, returns a formatter that respects the user's regional format settings, + // as configured by running intl.cpl. + DateTimeFormatter GetRegionalSettingsAwareDateTimeFormatter( string format, string calendarIdentifier, string clockIdentifier) + { + // UNO TODO + //IIterable languageIdentifiers = GetLanguageIdentifiers(); + //if (languageIdentifiers == null) + //{ + // languageIdentifiers = ApplicationLanguages.Languages; + //} + + //return new DateTimeFormatter(format, languageIdentifiers, GlobalizationPerences.HomeGeographicRegion, calendarIdentifier, clockIdentifier); + + throw new NotImplementedException(); + } + + public CurrencyFormatter GetRegionalSettingsAwareCurrencyFormatter() + { + // UNO TODO + //string userCurrency = + // (GlobalizationPreferences.Currencies.Size > 0) ? GlobalizationPreferences.Currencies.GetAt(0) : string(DefaultCurrencyCode.data()); + + //IIterable languageIdentifiers = GetLanguageIdentifiers(); + //if (languageIdentifiers == null) + //{ + // languageIdentifiers = ApplicationLanguages.Languages; + //} + + //var currencyFormatter = new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPerences.HomeGeographicRegion); + + //int fractionDigits = LocalizationSettings.GetInstance().GetCurrencyTrailingDigits(); + //currencyFormatter.FractionDigits = fractionDigits; + + //return currencyFormatter; + + throw new NotImplementedException(); + } + + static IEnumerable GetLanguageIdentifiers() + { +#if !HAS_UNO + //char currentLocale[LOCALE_NAME_MAX_LENGTH] = {}; + //int result = GetUserDefaultLocaleName(currentLocale, LOCALE_NAME_MAX_LENGTH); + //if (result != 0) + //{ + // // GetUserDefaultLocaleName may return an invalid bcp47 language tag with trailing non-BCP47 friendly characters, + // // which if present would start with an underscore, for example sort order + // // (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx). + // // Therefore, if there is an underscore in the locale name, trim all characters from the underscore onwards. + // WCHAR* underscore = wcschr(currentLocale, '_'); + // if (underscore != null) + // { + // *underscore = '\0'; + // } + + // string localestring = new String(currentLocale); + // // validate if the locale we have is valid + // // otherwise we fallback to the default. + // if (Language.IsWellFormed(localeString)) + // { + // var languageList = new Vector(); + // languageList.Append(localeString); + // return languageList; + // } + //} + + //return null; + yield break; +#else + yield break; +#endif + } + + // Resources for the engine use numbers as keys. It's inconvenient, but also difficult to + // change given that the engine heavily relies on perfect ordering of certain elements. + // To compromise, we'll declare a map from engine resource key to automation name from the + // standard project resources. + static (string, string)[] s_parenEngineKeyResourceMap = { // Sine permutations + ("67", "SineDegrees"), + ("73", "SineRadians"), + ("79", "SineGradians"), + ("70", "InverseSineDegrees"), + ("76", "InverseSineRadians"), + ("82", "InverseSineGradians"), + ("25", "HyperbolicSine"), + ("85", "InverseHyperbolicSine"), + + // Cosine permutations + ("68", "CosineDegrees"), + ("74", "CosineRadians"), + ("80", "CosineGradians"), + ("71", "InverseCosineDegrees"), + ("77", "InverseCosineRadians"), + ("83", "InverseCosineGradians"), + ("26", "HyperbolicCosine"), + ("86", "InverseHyperbolicCosine"), + + // Tangent permutations + ("69", "TangentDegrees"), + ("75", "TangentRadians"), + ("81", "TangentGradians"), + ("72", "InverseTangentDegrees"), + ("78", "InverseTangentRadians"), + ("84", "InverseTangentGradians"), + ("27", "HyperbolicTangent"), + ("87", "InverseHyperbolicTangent"), + + // Miscellaneous Scientific functions + ("94", "Factorial"), + ("35", "DegreeMinuteSecond"), + ("28", "NaturalLog"), + ("91", "Square") + }; + + static (string, string)[] s_noParenEngineKeyResourceMap = { // Programmer mode functions + ("9", "LeftShift"), + ("10", "RightShift"), + + // Y Root scientific function + ("16", "YRoot") + }; + + static Dictionary GetTokenToReadableNameMap() + { + Dictionary tokenToReadableNameMap = new Dictionary(); + var resProvider = AppResourceProvider.GetInstance(); + + string openParen = resProvider.GetCEngineString(s_openParenResourceKey); + + foreach (var keyPair in s_parenEngineKeyResourceMap) + { + string engineStr = resProvider.GetCEngineString(keyPair.Item1); + string automationName = resProvider.GetResourceString(keyPair.Item2); + + if (!tokenToReadableNameMap.ContainsKey(engineStr + openParen)) + { + tokenToReadableNameMap.Add(engineStr + openParen, automationName); + } + } + // s_parenEngineKeyResourceMap.clear(); + + foreach (var keyPair in s_noParenEngineKeyResourceMap) + { + string engineStr = resProvider.GetCEngineString(keyPair.Item1); + string automationName = resProvider.GetResourceString(keyPair.Item2); + + if (!tokenToReadableNameMap.ContainsKey(engineStr)) + { + tokenToReadableNameMap[engineStr] = automationName; + } + } + // s_noParenEngineKeyResourceMap.clear(); + + // Also replace hyphens with "minus" + string minusText = resProvider.GetResourceString("minus"); + + if (!tokenToReadableNameMap.ContainsKey("-")) + { + tokenToReadableNameMap["-"] = minusText; + } + + return tokenToReadableNameMap; + } + + static Dictionary s_tokenToReadableNameMap = GetTokenToReadableNameMap(); + + static readonly string openParen = AppResourceProvider.GetInstance().GetCEngineString(s_openParenResourceKey); + + public static string GetNarratorReadableToken(string rawToken) + { + if(s_tokenToReadableNameMap.TryGetValue(rawToken, out var itr)) + { + return itr + " " + openParen; + } + else + { + return rawToken; + } + } + + public static string GetNarratorReadableString(string rawString) + { + StringBuilder readableString = new StringBuilder(); + + string asWstring = rawString; + foreach (var c in asWstring) + { + readableString.Append(GetNarratorReadableToken("" + c)); + } + + return readableString.ToString(); + } + }; + +} diff --git a/src/Calculator.Shared/Common/LocalizationSettings.cs b/src/Calculator.Shared/Common/LocalizationSettings.cs new file mode 100644 index 00000000..5fe8f6b4 --- /dev/null +++ b/src/Calculator.Shared/Common/LocalizationSettings.cs @@ -0,0 +1,398 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using System; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +namespace CalculatorApp +{ + namespace Common + { + public class LocalizationSettings + { + const int LOCALE_NAME_MAX_LENGTH = 85; + const int LocaleSettingBufferSize = 16; + + public LocalizationSettings() + { +#if false + int result = 0; + + // Use DecimalFormatter as it respects the locale and the user setting + Windows.Globalization.NumberFormatting.DecimalFormatter formatter; + formatter = CalculatorApp.Common.LocalizationService.GetRegionalSettingsAwareDecimalFormatter(); + formatter.FractionDigits = 0; + formatter.IsDecimalPointAlwaysDisplayed = false; + + for (uint i = 0; i < 10; i++) + { + m_digitSymbols[i] = formatter.FormatUInt(i)[0]; + } + + char[] resolvedName = new char[LOCALE_NAME_MAX_LENGTH]; + result = ResolveLocaleName(formatter.ResolvedLanguage.Data(), resolvedName, LOCALE_NAME_MAX_LENGTH); + if (result == 0) + { + throw new Exception("Unexpected error resolving locale name"); + } + else + { + m_resolvedName = resolvedName; + char[] decimalString = new char[LocaleSettingBufferSize]; + result = GetLocaleInfoEx(m_resolvedName, LOCALE_SDECIMAL, decimalString, (int)(std.size(decimalString))); + if (result == 0) + { + throw new Exception("Unexpected error while getting locale info"); + } + + char[] groupingSymbolString = new char[LocaleSettingBufferSize]; + result = GetLocaleInfoEx(m_resolvedName, LOCALE_STHOUSAND, groupingSymbolString, (int)(std.size(groupingSymbolString))); + if (result == 0) + { + throw new Exception("Unexpected error while getting locale info"); + } + + char[] numberGroupingString = new char[LocaleSettingBufferSize]; + result = GetLocaleInfoEx(m_resolvedName, LOCALE_SGROUPING, numberGroupingString, (int)(std.size(numberGroupingString))); + if (result == 0) + { + throw new Exception("Unexpected error while getting locale info"); + } + + // Get locale info for List Separator, eg. comma is used in many locales + char[] listSeparatorString = new char[4]; + result = GetLocaleInfoEx( + LOCALE_NAME_USER_DEFAULT, + LOCALE_SLIST, + listSeparatorString, + (int)(std.size(listSeparatorString))); // Max length of the expected return value is 4 + if (result == 0) + { + throw new Exception("Unexpected error while getting locale info"); + } + + int currencyTrailingDigits = 0; + result = GetLocaleInfoEx( + m_resolvedName, + LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER, + (LPWSTR) & currencyTrailingDigits, + sizeof(currencyTrailingDigits) / sizeof(WCHAR)); + if (result == 0) + { + throw new Exception("Unexpected error while getting locale info"); + } + + // Currency symbol precedence is either 0 or 1. + // A value of 0 indicates the symbol follows the currency value. + int currencySymbolPrecedence = 1; + result = GetLocaleInfoEx( + LOCALE_NAME_USER_DEFAULT, + LOCALE_IPOSSYMPRECEDES | LOCALE_RETURN_NUMBER, + (LPWSTR) & currencySymbolPrecedence, + sizeof(currencySymbolPrecedence) / sizeof(WCHAR)); + + // As CalcEngine only supports the first character of the decimal separator, + // Only first character of the decimal separator string is supported. + m_decimalSeparator = decimalString[0]; + m_numberGroupSeparator = groupingSymbolString[0]; + m_numberGrouping = numberGroupingString; + m_listSeparator = listSeparatorString; + m_currencyTrailingDigits = currencyTrailingDigits; + m_currencySymbolPrecedence = currencySymbolPrecedence; + } + + // Get the system calendar type + // Note: This function returns 0 on failure. + // We'll ignore the failure in that case and the CalendarIdentifier would get set to GregorianCalendar. + CALID calId; + GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER, reinterpret_cast(&calId), sizeof(calId)); + + m_calendarIdentifier = GetCalendarIdentifierFromCalid(calId); + + // Get FirstDayOfWeek Date and Time setting + char day[80] = ""; + GetLocaleInfoEx( + LOCALE_NAME_USER_DEFAULT, + LOCALE_IFIRSTDAYOFWEEK, // The first day in a week + reinterpret_cast(day), // Argument is of type PWSTR + (int)(std.size(day))); // Max return size are 80 characters + + // The LOCALE_IFIRSTDAYOFWEEK integer value varies from 0, 1, .. 6 for Monday, Tuesday, ... Sunday + // DayOfWeek enum value varies from 0, 1, .. 6 for Sunday, Monday, ... Saturday + // Hence, DayOfWeek = (valueof(LOCALE_IFIRSTDAYOFWEEK) + 1) % 7 + m_firstDayOfWeek = (Windows.Globalization.DayOfWeek)((_wtoi(day) + 1) % 7); // static cast int to DayOfWeek enum +#else + for (uint i = 0; i < 10; i++) + { + m_digitSymbols[i] = i.ToString(NumberFormatInfo.CurrentInfo)[0]; + } + + // As CalcEngine only supports the first character of the decimal separator, + // Only first character of the decimal separator string is supported. + m_decimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0]; + m_numberGroupSeparator = NumberFormatInfo.CurrentInfo.NumberGroupSeparator[0]; + m_numberGrouping = ""; // UNO TODO https://docs.microsoft.com/en-us/windows/desktop/Intl/locale-sgrouping + m_listSeparator = CultureInfo.CurrentCulture.TextInfo.ListSeparator; + m_currencyTrailingDigits = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits; + m_currencySymbolPrecedence = ~(NumberFormatInfo.CurrentInfo.CurrencyPositivePattern) & 1; + + m_calendarIdentifier = "";//CultureInfo.CurrentCulture.DateTimeFormat.Calendar.ToString(); + + m_firstDayOfWeek = (Windows.Globalization.DayOfWeek)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; +#endif + } + + static LocalizationSettings m_localizationSettings; + + // Provider of the singleton LocalizationSettings instance. + public static LocalizationSettings GetInstance() + { + if(m_localizationSettings== null) + { + m_localizationSettings = new LocalizationSettings(); + } + return m_localizationSettings; + } + + string GetLocaleName() + { + return m_resolvedName; + } + + bool IsDigitEnUsSetting() + { + if (this.GetDigitSymbolFromEnUsDigit('0') == '0') + { + return true; + } + return false; + } + + public void LocalizeDisplayValue(ref string stringToLocalize) + { + var b = new StringBuilder(); + + if (IsDigitEnUsSetting()) + { + return; + } + + foreach (char ch in stringToLocalize) + { + if (IsEnUsDigit(ch)) + { + b.Append(GetDigitSymbolFromEnUsDigit(ch)); + } + else + { + b.Append(ch); + } + } + + stringToLocalize = b.ToString(); + } + + public string GetEnglishValueFromLocalizedDigits(string localizedString) + { + if (m_resolvedName == "en-US") + { + return localizedString; + } + + int i = 0; + int length = localizedString.Length; + char[] englishString = new char[length + 1]; // +1 for the null termination + + for (; i < length; ++i) + { + char ch = localizedString[i]; + if (!IsEnUsDigit(ch)) + { + for (int j = 0; j < 10; ++j) + { + if (ch == m_digitSymbols[j]) + { + ch = j.ToString()[0]; + break; + // ch = val - '0'; + } + } + } + if (ch == m_decimalSeparator) + { + ch = '.'; + } + englishString[i] = ch; + } + englishString[i] = '\0'; + + return new string(englishString); + } + + public bool IsEnUsDigit(char digit) + { + if (digit >= '0' && digit <= '9') + { + return true; + } + return false; + } + + public bool IsLocalizedDigit(char digit) + { + foreach(var dig in m_digitSymbols) + { + if (digit == dig) + { + return true; + } + } + return false; + } + + public bool IsLocalizedHexDigit(char digit) + { + if (IsLocalizedDigit(digit)) + { + return true; + } + + foreach(var dig in s_hexSymbols) + { + if (digit == dig) + { + return true; + } + } + + return false; + } + + public char GetDigitSymbolFromEnUsDigit(char digitSymbol) + { + Debug.Assert(digitSymbol >= '0' && digitSymbol <= '9'); + int digit = digitSymbol - '0'; + return m_digitSymbols[digit]; // throws on out of range + } + + public char GetDecimalSeparator() + { + return m_decimalSeparator; + } + + char GetNumberGroupSeparator() + { + return m_numberGroupSeparator; + } + + public string GetDecimalSeparatorStr() + { + return m_decimalSeparator.ToString(); + } + + public string GetNumberGroupingSeparatorStr() + { + return m_numberGroupSeparator.ToString(); + } + + public string GetNumberGroupingStr() + { + return m_numberGrouping; + } + + public void RemoveGroupSeparators(string value, int length, ref string rawValue) + { + StringBuilder b = new StringBuilder(length); + + for (int i = 0; i < length; i++) + { + if (value[i] != ' ' && value[i] != m_numberGroupSeparator) + { + b.Append(value[i]); + } + } + + rawValue = b.ToString(); + } + + public string GetCalendarIdentifier() + { + return m_calendarIdentifier; + } + + public string GetListSeparator() + { + return m_listSeparator; + } + + Windows.Globalization.DayOfWeek GetFirstDayOfWeek() + { + return m_firstDayOfWeek; + } + + public int GetCurrencyTrailingDigits() + { + return m_currencyTrailingDigits; + } + + int GetCurrencySymbolPrecedence() + { + return m_currencySymbolPrecedence; + } + + public static string GetCalendarIdentifierFromCalid(int calId) + { + switch (calId) + { + //case CAL_GREGORIAN: + //case CAL_GREGORIAN_ARABIC: + //case CAL_GREGORIAN_ME_FRENCH: + //case CAL_GREGORIAN_US: + //case CAL_GREGORIAN_XLIT_ENGLISH: + //case CAL_GREGORIAN_XLIT_FRENCH: + // return Windows.Globalization.CalendarIdentifiers.Gregorian; + + //case CAL_HEBREW: + // return Windows.Globalization.CalendarIdentifiers.Hebrew; + + //case CAL_HIJRI: + //case CAL_PERSIAN: + // return Windows.Globalization.CalendarIdentifiers.Hijri; + + //case CAL_JAPAN: + // return Windows.Globalization.CalendarIdentifiers.Japanese; + + //case CAL_KOREA: + // return Windows.Globalization.CalendarIdentifiers.Korean; + + //case CAL_TAIWAN: + // return Windows.Globalization.CalendarIdentifiers.Taiwan; + + //case CAL_THAI: + // return Windows.Globalization.CalendarIdentifiers.Thai; + + //case CAL_UMALQURA: + // return Windows.Globalization.CalendarIdentifiers.UmAlQura; + + // Gregorian will be the default Calendar Type + default: + return Windows.Globalization.CalendarIdentifiers.Gregorian; + } + } + + char m_decimalSeparator; + char m_numberGroupSeparator; + string m_numberGrouping; + char[] m_digitSymbols = new char[10]; + // Hexadecimal characters are not currently localized + static char[] s_hexSymbols = { 'A', 'B', 'C', 'D', 'E', 'F' }; + string m_listSeparator; + string m_calendarIdentifier; + Windows.Globalization.DayOfWeek m_firstDayOfWeek; + int m_currencySymbolPrecedence; + string m_resolvedName; + int m_currencyTrailingDigits; + } + } +} diff --git a/src/Calculator.Shared/Common/LocalizationStringUtil.cs b/src/Calculator.Shared/Common/LocalizationStringUtil.cs new file mode 100644 index 00000000..61053fed --- /dev/null +++ b/src/Calculator.Shared/Common/LocalizationStringUtil.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace CalculatorApp +{ + namespace Common + { + public static class LocalizationStringUtil + { + public static string GetLocalizedString(string pMessage, params object[] args) + { + // UNO TODO + + //string returnString = ""; + //const uint length = 1024; + //std.unique_ptr spBuffer = std.unique_ptr(new wchar_t[length]); + //va_list args = NULL; + //va_start(args, pMessage); + //int fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING, pMessage, 0, 0, spBuffer.get(), length, &args); + //va_end(args); + + //if (fmtReturnVal != 0) + //{ + // returnString = spBuffer.get(); + //} + + //return returnString; + + return $"[{pMessage}]"; + } + + public static string GetLocalizedNarratorAnnouncement(string resourceKey, string formatVariable, params object[] args) + { + EnsureInitialization(resourceKey, formatVariable); + return GetLocalizedString(formatVariable, args); + } + + static void EnsureInitialization(string resourceKey, string formatVariable) + { + if (resourceKey == null || string.IsNullOrEmpty(resourceKey)) + { + return; + } + + // If the formatVariable already has a value, we don't need to set it again. Simply return. + if (formatVariable != null && !string.IsNullOrEmpty(formatVariable)) + { + return; + } + + formatVariable = AppResourceProvider.GetInstance().GetResourceString(resourceKey); + } + } + } +} diff --git a/src/CalcViewModel/Common/MyVirtualKey.h b/src/Calculator.Shared/Common/MyVirtualKey.cs similarity index 98% rename from src/CalcViewModel/Common/MyVirtualKey.h rename to src/Calculator.Shared/Common/MyVirtualKey.cs index c530e816..0a010dc0 100644 --- a/src/CalcViewModel/Common/MyVirtualKey.h +++ b/src/Calculator.Shared/Common/MyVirtualKey.cs @@ -1,14 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. - -#pragma once - namespace CalculatorApp { namespace Common { - public - enum class MyVirtualKey + public enum MyVirtualKey { None = 0, LeftButton = 1, diff --git a/src/Calculator.Shared/Common/NavCategory.cs b/src/Calculator.Shared/Common/NavCategory.cs new file mode 100644 index 00000000..50176886 --- /dev/null +++ b/src/Calculator.Shared/Common/NavCategory.cs @@ -0,0 +1,608 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/* The NavCategory group of classes and enumerations is intended to serve + * as a single location for storing metadata about a navigation mode. + * + * These .h and .cpp files: + * - Define the ViewMode enumeration which is used for setting the mode of the app. + * - Define a list of metadata associated with each ViewMode. + * - Define the order of groups and items in the navigation menu. + * - Provide a static helper function for creating the navigation menu options. + * - Provide static helper functions for querying information about a given ViewMode. + */ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using Windows.Foundation.Collections; + +namespace CalculatorApp +{ + namespace Common + { + // Don't change the order of these enums + // and definitely don't use int arithmetic + // to change modes. + public enum ViewMode + { + None = -1, + Standard = 0, + Scientific = 1, + Programmer = 2, + Date = 3, + Volume = 4, + Length = 5, + Weight = 6, + Temperature = 7, + Energy = 8, + Area = 9, + Speed = 10, + Time = 11, + Power = 12, + Data = 13, + Pressure = 14, + Angle = 15, + Currency = 16 + }; + + public enum CategoryGroupType + { + None = -1, + Calculator = 0, + Converter = 1 + }; + + + struct NavCategoryInitializer + { + public NavCategoryInitializer( + ViewMode mode, + int id, + string name, + string nameKey, + string glyph, + CategoryGroupType group, + MyVirtualKey vKey, + bool categorySupportsNegative) + { + this.viewMode = mode; + this.serializationId = id; + this.friendlyName = name; + this.nameResourceKey = nameKey; + this.glyph = glyph; + this.groupType = group; + this.virtualKey = vKey; + this.supportsNegative = categorySupportsNegative; + } + + public readonly ViewMode viewMode; + public readonly int serializationId; + public readonly string friendlyName; + public readonly string nameResourceKey; + public readonly string glyph; + public readonly CategoryGroupType groupType; + public readonly MyVirtualKey virtualKey; + public readonly bool supportsNegative; + }; + + internal struct NavCategoryGroupInitializer + { + public NavCategoryGroupInitializer(CategoryGroupType t, string h, string n, string a) + { + type = t; + headerResourceKey = h; + modeResourceKey = n; + automationResourceKey = a; + } + + public readonly CategoryGroupType type; + public readonly string headerResourceKey; + public readonly string modeResourceKey; + public readonly string automationResourceKey; + }; + + [Windows.UI.Xaml.Data.Bindable] + public sealed class NavCategory : INotifyPropertyChanged + { + + + + + public event PropertyChangedEventHandler PropertyChanged; + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); + + public string Name => m_name; + + public string AutomationName => m_varmationName; + + public string Glyph => m_glyph; + + int Position + { + get + { + return m_position; + } + } + + public ViewMode Mode + { + get + { + return m_viewMode; + } + } + + public string AutomationId => m_viewMode.ToString(); + + public string AccessKey => m_accessKey; + + bool SupportsNegative + { + get + { + return m_supportsNegative; + } + } + + internal NavCategory( + string name, + string varmationName, + string glyph, + string accessKey, + string mode, + ViewMode viewMode, + bool supportsNegative) + + { + m_name = name; + m_varmationName = varmationName; + m_glyph = glyph; + m_accessKey = accessKey; + m_mode = mode; + m_viewMode = viewMode; + m_supportsNegative = supportsNegative; + m_position = GetPosition(m_viewMode); + } + + ViewMode m_viewMode; + string m_name; + string m_varmationName; + string m_glyph; + string m_accessKey; + string m_mode; + int m_position; + bool m_supportsNegative; + + + // Calculator categories always support negative and positive. + const bool SUPPORTS_ALL = true; + + // Converter categories usually only support positive. + const bool SUPPORTS_NEGATIVE = true; + const bool POSITIVE_ONLY = false; + + // The order of items in this list determines the order of groups in the menu. + internal static NavCategoryGroupInitializer?[] s_categoryGroupManifest = { + new NavCategoryGroupInitializer( CategoryGroupType.Calculator, "CalculatorModeTextCaps", "CalculatorModeText", "CalculatorModePluralText" ), + new NavCategoryGroupInitializer( CategoryGroupType.Converter, "ConverterModeTextCaps", "ConverterModeText", "ConverterModePluralText" ) + }; + + // vvv THESE CONSTANTS SHOULD NEVER CHANGE vvv + const int STANDARD_ID = 0; + const int SCIENTIFIC_ID = 1; + const int PROGRAMMER_ID = 2; + const int DATE_ID = 3; + const int VOLUME_ID = 4; + const int LENGTH_ID = 5; + const int WEIGHT_ID = 6; + const int TEMPERATURE_ID = 7; + const int ENERGY_ID = 8; + const int AREA_ID = 9; + const int SPEED_ID = 10; + const int TIME_ID = 11; + const int POWER_ID = 12; + const int DATA_ID = 13; + const int PRESSURE_ID = 14; + const int ANGLE_ID = 15; + const int CURRENCY_ID = 16; + //^^ THESE CONSTANTS SHOULD NEVER CHANGE^^ + + + internal static NavCategoryInitializer?[] s_categoryManifest = { new NavCategoryInitializer( ViewMode.Standard, + STANDARD_ID, + "Standard", + "StandardMode", + "\uE8EF", + CategoryGroupType.Calculator, + MyVirtualKey.Number1, + SUPPORTS_ALL ), + new NavCategoryInitializer( ViewMode.Scientific, + SCIENTIFIC_ID, + "Scientific", + "ScientificMode", + "\uF196", + CategoryGroupType.Calculator, + MyVirtualKey.Number2, + SUPPORTS_ALL ), + new NavCategoryInitializer( ViewMode.Programmer, + PROGRAMMER_ID, + "Programmer", + "ProgrammerMode", + "\uECCE", + CategoryGroupType.Calculator, + MyVirtualKey.Number3, + SUPPORTS_ALL ), + new NavCategoryInitializer( ViewMode.Date, + DATE_ID, + "Date", + "DateCalculationMode", + "\uE787", + CategoryGroupType.Calculator, + MyVirtualKey.Number4, + SUPPORTS_ALL ), + new NavCategoryInitializer( ViewMode.Currency, + CURRENCY_ID, + "Currency", + "CategoryName_Currency", + "\uEB0D", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Volume, + VOLUME_ID, + "Volume", + "CategoryName_Volume", + "\uF1AA", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Length, + LENGTH_ID, + "Length", + "CategoryName_Length", + "\uECC6", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Weight, + WEIGHT_ID, + "Weight and Mass", + "CategoryName_Weight", + "\uF4C1", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Temperature, + TEMPERATURE_ID, + "Temperature", + "CategoryName_Temperature", + "\uE7A3", + CategoryGroupType.Converter, + MyVirtualKey.None, + SUPPORTS_NEGATIVE ), + new NavCategoryInitializer( ViewMode.Energy, + ENERGY_ID, + "Energy", + "CategoryName_Energy", + "\uECAD", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Area, + AREA_ID, + "Area", + "CategoryName_Area", + "\uE809", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Speed, + SPEED_ID, + "Speed", + "CategoryName_Speed", + "\uEADA", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Time, + TIME_ID, + "Time", + "CategoryName_Time", + "\uE917", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Power, + POWER_ID, + "Power", + "CategoryName_Power", + "\uE945", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Data, + DATA_ID, + "Data", + "CategoryName_Data", + "\uF20F", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Pressure, + PRESSURE_ID, + "Pressure", + "CategoryName_Pressure", + "\uEC4A", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ), + new NavCategoryInitializer( ViewMode.Angle, + ANGLE_ID, + "Angle", + "CategoryName_Angle", + "\uF515", + CategoryGroupType.Converter, + MyVirtualKey.None, + POSITIVE_ONLY ) }; + + // This function should only be used when storing the mode to app data. + public static int Serialize(ViewMode mode) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.viewMode == mode); + + return iter != null ? iter.Value.serializationId : -1; + } + + // This function should only be used when restoring the mode from app data. + static public ViewMode Deserialize(object obj) + { + // If we cast directly to ViewMode we will fail + // because we technically store an int. + // Need to cast to int, then ViewMode. + var boxed = (int)(obj); + if (obj is int serializationId) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.serializationId == serializationId); + + if (iter != null) + { + return iter.Value.viewMode; + } + } + + return ViewMode.None; + } + + public static bool IsValidViewMode(ViewMode mode) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.viewMode == mode); + + return iter != null; + } + + public static bool 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); + } + + public static bool IsDateCalculatorViewMode(ViewMode mode) + { + return mode == ViewMode.Date; + } + + public static bool IsConverterViewMode(ViewMode mode) + { + return IsModeInCategoryGroup(mode, CategoryGroupType.Converter); + } + + public static bool IsModeInCategoryGroup(ViewMode mode, CategoryGroupType type) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.viewMode == mode && c.Value.groupType == type); + + return iter != null; + } + + string GetFriendlyName(ViewMode mode) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.viewMode == mode); + + return (iter != null) ? iter.Value.friendlyName : "None"; + } + + ViewMode GetViewModeForFriendlyName(string name) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.friendlyName == name); + + return (iter != null) ? iter.Value.viewMode : ViewMode.None; + } + + public static string GetNameResourceKey(ViewMode mode) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.viewMode == mode); + + return (iter != null) ? iter.Value.nameResourceKey + "Text" : null; + } + + public static CategoryGroupType GetGroupType(ViewMode mode) + { + var iter = s_categoryManifest.FirstOrDefault(c => c.Value.viewMode == mode); + + return (iter != null) ? iter.Value.groupType : CategoryGroupType.None; + } + + // GetIndex is 0-based, GetPosition is 1-based + int GetIndex(ViewMode mode) + { + int position = GetPosition(mode); + return Math.Max(-1, position - 1); + } + + public static int GetFlatIndex(ViewMode mode) + { + int index = -1; + CategoryGroupType type = CategoryGroupType.None; + var iter = s_categoryManifest.FirstOrDefault(initializer => { + index++; + if (initializer.Value.groupType != type) + { + type = initializer.Value.groupType; + index++; + } + + return initializer.Value.viewMode == mode; + }); + + return (iter != null) ? index : -1; + } + + // GetIndex is 0-based, GetPosition is 1-based + public static int GetIndexInGroup(ViewMode mode, CategoryGroupType type) + { + int index = -1; + var iter = s_categoryManifest.FirstOrDefault(initializer => + { + if (initializer.Value.groupType == type) + { + index++; + return initializer.Value.viewMode == mode; + } + + return false; + }); + + return (iter != null) ? index : -1; + } + + // GetIndex is 0-based, GetPosition is 1-based + int GetPosition(ViewMode mode) + { + int position = 0; + var iter = s_categoryManifest.FirstOrDefault(initializer => + { + position++; + return initializer.Value.viewMode == mode; + }); + + return (iter != null) ? position : -1; + } + + ViewMode GetViewModeForVirtualKey(MyVirtualKey virtualKey) + { + var iter = s_categoryManifest.FirstOrDefault(initializer => initializer.Value.virtualKey == virtualKey); + + return (iter != null) ? iter.Value.viewMode : ViewMode.None; + } + + public List GetCategoryAcceleratorKeys() + { + List accelerators = new List(); + foreach (var category in s_categoryManifest) + { + if (category.Value.virtualKey != MyVirtualKey.None) + { + accelerators.Add(category.Value.virtualKey); + } + } + + return accelerators; + } + }; + + [Windows.UI.Xaml.Data.Bindable] + public sealed class NavCategoryGroup : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); + private string m_Name; + public string Name { get => m_Name; private set { m_Name = value; RaisePropertyChanged("Name"); } } + + + private string m_AutomationName; + public string AutomationName { get => m_AutomationName; private set { m_AutomationName = value; RaisePropertyChanged("AutomationName"); } } + + + private CategoryGroupType m_GroupType; + public CategoryGroupType GroupType { get => m_GroupType; private set { m_GroupType = value; RaisePropertyChanged("GroupType"); } } + + + private ObservableCollection m_Categories; + public ObservableCollection Categories { get => m_Categories; private set { m_Categories = value; RaisePropertyChanged("Categories"); } } + + + internal NavCategoryGroup(NavCategoryGroupInitializer groupInitializer) + { + m_Categories = new ObservableCollection(); + m_GroupType = groupInitializer.type; + + var resProvider = AppResourceProvider.GetInstance(); + string headerResourceKey = (groupInitializer.headerResourceKey); + string modeResourceKey = (groupInitializer.modeResourceKey); + string automationResourceKey = (groupInitializer.automationResourceKey); + m_Name = resProvider.GetResourceString(headerResourceKey); + string groupMode = resProvider.GetResourceString(modeResourceKey); + string automationName = resProvider.GetResourceString(automationResourceKey); + + string navCategoryHeaderAutomationNameFormat = resProvider.GetResourceString("NavCategoryHeader_AutomationNameFormat"); + m_AutomationName = LocalizationStringUtil.GetLocalizedString(navCategoryHeaderAutomationNameFormat, automationName); + + string navCategoryItemAutomationNameFormat = resProvider.GetResourceString("NavCategoryItem_AutomationNameFormat"); + + foreach (NavCategoryInitializer? categoryInitializer in NavCategory.s_categoryManifest) + { + if (categoryInitializer.Value.groupType == groupInitializer.type) + { + string nameResourceKey = (categoryInitializer.Value.nameResourceKey); + string categoryName = resProvider.GetResourceString(nameResourceKey + "Text"); + string categoryAutomationName = LocalizationStringUtil.GetLocalizedString(navCategoryItemAutomationNameFormat, categoryName, m_Name); + + m_Categories.Append( new NavCategory( + categoryName, + categoryAutomationName, + (categoryInitializer.Value.glyph), + resProvider.GetResourceString(nameResourceKey + "AccessKey"), + groupMode, + categoryInitializer.Value.viewMode, + categoryInitializer.Value.supportsNegative)); + } + } + } + + public static ObservableCollection CreateMenuOptions() + { + var menuOptions = new ObservableCollection(); + menuOptions.Add(CreateCalculatorCategory()); + menuOptions.Add(CreateConverterCategory()); + return menuOptions; + } + + static NavCategoryGroup CreateCalculatorCategory() + { + return new NavCategoryGroup(NavCategory.s_categoryGroupManifest[0].Value); + } + + static NavCategoryGroup CreateConverterCategory() + { + return new NavCategoryGroup(NavCategory.s_categoryGroupManifest[1].Value); + } + + List GetInitializerCategoryGroup(CategoryGroupType groupType) + { + return new List( + NavCategory.s_categoryManifest.Where(initializer => initializer.Value.groupType == groupType).Select(i => i.Value)); + } + + string GetHeaderResourceKey(CategoryGroupType type) + { + var iter = NavCategory.s_categoryGroupManifest.FirstOrDefault(initializer => initializer.Value.type == type); + + return (iter != null) ? (iter.Value.headerResourceKey) : null; + } + } + } +} diff --git a/src/Calculator.Shared/Common/TitleBarHelper.cs b/src/Calculator.Shared/Common/TitleBarHelper.cs new file mode 100644 index 00000000..43319c57 --- /dev/null +++ b/src/Calculator.Shared/Common/TitleBarHelper.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WindowsCalculator.Shared.Common +{ + class TitleBarHelper + { + } +} diff --git a/src/Calculator.Shared/Common/Utils.cs b/src/Calculator.Shared/Common/Utils.cs new file mode 100644 index 00000000..158784e8 --- /dev/null +++ b/src/Calculator.Shared/Common/Utils.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Windows.UI.Core; +using Windows.UI.ViewManagement; + +namespace CalculatorApp +{ + public static class Utils + { + public const char LRE = (char)0x202a; // Left-to-Right Embedding + public const char PDF = (char)0x202c; // Pop Directional Formatting + public const char LRO = (char)0x202d; // Left-to-Right Override + + // Returns windowId for the current view + public static int GetWindowId() + { + int windowId = -1; + + var window = CoreWindow.GetForCurrentThread(); + if (window != null) + { + windowId = ApplicationView.GetApplicationViewIdForWindow(window); + } + + return windowId; + } + + public static bool IsLastCharacterTarget(string input, char target) + { + return !string.IsNullOrEmpty(input) && input.Last() == target; + } + } +} diff --git a/src/Calculator.Shared/Controls/CalculationResult.cs b/src/Calculator.Shared/Controls/CalculationResult.cs new file mode 100644 index 00000000..eee528ed --- /dev/null +++ b/src/Calculator.Shared/Controls/CalculationResult.cs @@ -0,0 +1,538 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp.Common; +using System; +using System.Diagnostics; +using Windows.Devices.Input; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp +{ + namespace Controls + { + public delegate void SelectedEventHandler(object sender); + + public sealed partial class CalculationResult : Windows.UI.Xaml.Controls.Control + { + public Visibility ExpressionVisibility + { + get { return (Visibility)GetValue(ExpressionVisibilityProperty); } + set { SetValue(ExpressionVisibilityProperty, value); } + } + + public static readonly DependencyProperty ExpressionVisibilityProperty = + DependencyProperty.Register("ExpressionVisibility", typeof(Visibility), typeof(CalculationResult), new PropertyMetadata(Visibility.Collapsed)); + + + + public double MinFontSize + { + get { return (double)GetValue(MinFontSizeProperty); } + set { SetValue(MinFontSizeProperty, value); } + } + + public static readonly DependencyProperty MinFontSizeProperty = + DependencyProperty.Register("MinFontSize", typeof(double), typeof(CalculationResult), new PropertyMetadata(0.0)); + + + + public double MaxFontSize + { + get { return (double)GetValue(MaxFontSizeProperty); } + set { SetValue(MaxFontSizeProperty, value); } + } + + public static readonly DependencyProperty MaxFontSizeProperty = + DependencyProperty.Register("MaxFontSize", typeof(double), typeof(CalculationResult), new PropertyMetadata(30.0)); + + + + public Thickness DisplayMargin + { + get { return (Thickness)GetValue(DisplayMarginProperty); } + set { SetValue(DisplayMarginProperty, value); } + } + + public static readonly DependencyProperty DisplayMarginProperty = + DependencyProperty.Register("DisplayMargin", typeof(Thickness), typeof(CalculationResult), new PropertyMetadata(default(Thickness))); + + + + public int MaxExpressionHistoryCharacters + { + get { return (int)GetValue(MaxExpressionHistoryCharactersProperty); } + set { SetValue(MaxExpressionHistoryCharactersProperty, value); } + } + + public static readonly DependencyProperty MaxExpressionHistoryCharactersProperty = + DependencyProperty.Register("MaxExpressionHistoryCharacters", typeof(int), typeof(CalculationResult), new PropertyMetadata(0)); + + + + public bool IsActive + { + get { return (bool)GetValue(IsActiveProperty); } + set { SetValue(IsActiveProperty, value); } + } + + public static readonly DependencyProperty IsActiveProperty = + DependencyProperty.Register("IsActive", typeof(bool), typeof(CalculationResult), new PropertyMetadata(false)); + + + + + public string DisplayValue + { + get { return (string)GetValue(DisplayValueProperty); } + set { SetValue(DisplayValueProperty, value); } + } + + // Using a DependencyProperty as the backing store for DisplayValue. This enables animation, styling, binding, etc... + public static readonly DependencyProperty DisplayValueProperty = + DependencyProperty.Register("DisplayValue", typeof(string), typeof(CalculationResult), new PropertyMetadata("")); + + + + public string DisplayStringExpression + { + get { return (string)GetValue(DisplayStringExpressionProperty); } + set { SetValue(DisplayStringExpressionProperty, value); } + } + + // Using a DependencyProperty as the backing store for DisplayStringExpression. This enables animation, styling, binding, etc... + public static readonly DependencyProperty DisplayStringExpressionProperty = + DependencyProperty.Register("DisplayStringExpression", typeof(string), typeof(CalculationResult), new PropertyMetadata("")); + + public bool IsInError + { + get { return (bool)GetValue(IsInErrorProperty); } + set { SetValue(IsInErrorProperty, value); } + } + + // Using a DependencyProperty as the backing store for IsInError. This enables animation, styling, binding, etc... + public static readonly DependencyProperty IsInErrorProperty = + DependencyProperty.Register("IsInError", typeof(bool), typeof(CalculationResult), new PropertyMetadata(false)); + + + + public bool IsOperatorCommand + { + get { return (bool)GetValue(IsOperatorCommandProperty); } + set { SetValue(IsOperatorCommandProperty, value); } + } + + // Using a DependencyProperty as the backing store for IsOperatorCommand. This enables animation, styling, binding, etc... + public static readonly DependencyProperty IsOperatorCommandProperty = + DependencyProperty.Register("IsOperatorCommand", typeof(bool), typeof(CalculationResult), new PropertyMetadata(false)); + + event SelectedEventHandler Selected; + + + private Windows.UI.Xaml.Controls.ScrollViewer m_textContainer; + private Windows.UI.Xaml.Controls.TextBlock m_textBlock; + private Windows.UI.Xaml.Controls.HyperlinkButton m_scrollLeft; + private Windows.UI.Xaml.Controls.HyperlinkButton m_scrollRight; + private double scrollRatio = 0.7; + private bool m_isScalingText; + private bool m_haveCalculatedMax; + + + + const double SCALEFACTOR = 0.357143; + const int SMALLHEIGHTSCALEFACTOR = 0; + const int HEIGHTCUTOFF = 100; + const int INCREMENTOFFSET = 1; + const int MAXFONTINCREMENT = 5; + const double WIDTHTOFONTSCALAR = 0.0556513; + const int WIDTHTOFONTOFFSET = 3; + const int WIDTHCUTOFF = 50; + const double FONTTOLERANCE = 0.001; + + // Visual states for focused + static string s_FocusedState = "Focused"; + static string s_UnfocusedState = "Unfocused"; + + public CalculationResult() + { + m_isScalingText = false; + m_haveCalculatedMax = false; + } + + string GetRawDisplayValue() + { + string rawValue = null; + + LocalizationSettings.GetInstance().RemoveGroupSeparators(DisplayValue, DisplayValue.Length, ref rawValue); + + return rawValue; + } + + protected override void OnApplyTemplate() + { + System.Diagnostics.Debug.Assert((m_scrollLeft == null && m_scrollRight == null) || (m_scrollLeft != null && m_scrollRight != null)); + if (m_textContainer != null) + { + // UNO TODO + // m_textContainer.LayoutUpdated -= m_textContainerLayoutChangedToken; + } + m_textContainer = (ScrollViewer)(GetTemplateChild("TextContainer")); + if (m_textContainer != null) + { + m_textContainer.SizeChanged += TextContainerSizeChanged; + // We want to know when the size of the container changes so + // we can rescale the textbox + m_textContainer.LayoutUpdated += OnTextContainerLayoutUpdated; + + m_textContainer.ChangeView(m_textContainer.ExtentWidth - m_textContainer.ViewportWidth, null, null); + m_scrollLeft = (HyperlinkButton)(GetTemplateChild("ScrollLeft")); + m_scrollRight = (HyperlinkButton)(GetTemplateChild("ScrollRight")); + var borderContainer = (UIElement)(GetTemplateChild("Border")); + if (m_scrollLeft != null && m_scrollRight != null) + { + m_scrollLeft.Click += OnScrollClick; + m_scrollRight.Click += OnScrollClick; + borderContainer.PointerEntered += OnPointerEntered; + borderContainer.PointerExited += OnPointerExited; + } + m_textBlock = (TextBlock)(m_textContainer.FindName("NormalOutput")); + if (m_textBlock != null) + { + m_textBlock.Visibility = Visibility.Visible; + } + } + UpdateAllState(); + VisualStateManager.GoToState(this, s_UnfocusedState, false); + } + + void OnPointerPressed(PointerRoutedEventArgs e) + { + if (m_scrollLeft != null && m_scrollRight != null && e.Pointer.PointerDeviceType == PointerDeviceType.Touch) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Collapsed); + } + } + + void OnTextContainerLayoutUpdated(object sender, object e) + { + if (m_isScalingText) + { + UpdateTextState(); + } + } + + void TextContainerSizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateTextState(); + } + + void OnIsActivePropertyChanged(bool oldValue, bool newValue) + { + UpdateVisualState(); + } + + void OnAccentColorPropertyChanged(Brush oldValue, Brush newValue) + { + // Force the "Active" transition to happen again + if (IsActive) + { + VisualStateManager.GoToState(this, "Normal", true); + VisualStateManager.GoToState(this, "Active", true); + } + } + + void OnDisplayValuePropertyChanged(string oldValue, string newValue) + { + UpdateTextState(); + } + + void OnMinFontSizePropertyChanged(double oldValue, double newValue) + { + UpdateTextState(); + } + + void OnMaxFontSizePropertyChanged(double oldValue, double newValue) + { + UpdateTextState(); + } + + void OnIsInErrorPropertyChanged(bool oldValue, bool newValue) + { + // We need to have a good template for this to work + if (m_textBlock == null) + { + return; + } + + if (newValue) + { + // If there's an error message we need to override the normal display font + // with the font appropriate for this language. This is because the error + // message is localized and therefore can contain characters that are not + // available in the normal font. + // We use UIText as the font type because this is the most common font type to use + m_textBlock.FontFamily = LocalizationService.GetInstance().GetLanguageFontFamilyForType(LanguageFontType.UIText); + } + else + { + // The error result is no longer an error so we will restore the + // value to FontFamily property to the value provided in the style + // for the TextBlock in the template. + m_textBlock.ClearValue(TextBlock.FontFamilyProperty); + } + } + + void UpdateVisualState() + { + if (IsActive) + { + VisualStateManager.GoToState(this, "Active", true); + } + else + { + VisualStateManager.GoToState(this, "Normal", true); + } + } + + void UpdateTextState() + { + if ((m_textContainer == null) || (m_textBlock == null)) + { + return; + } + + var containerSize = m_textContainer.ActualWidth; + string oldText = m_textBlock.Text; + string newText = Utils.LRO + DisplayValue + Utils.PDF; + + // Initiate the scaling operation + // UpdateLayout will keep calling us until we make it through the below 2 if-statements + if (!m_isScalingText || oldText != newText) + { + m_textBlock.Text = newText; + + m_isScalingText = true; + m_haveCalculatedMax = false; + m_textBlock.InvalidateArrange(); + return; + } + if (containerSize > 0) + { + double widthDiff = Math.Abs(m_textBlock.ActualWidth - containerSize); + double fontSizeChange = INCREMENTOFFSET; + + if (widthDiff > WIDTHCUTOFF) + { + fontSizeChange = Math.Min(Math.Max(Math.Floor(WIDTHTOFONTSCALAR * widthDiff) - WIDTHTOFONTOFFSET, INCREMENTOFFSET), MAXFONTINCREMENT); + } + if (m_textBlock.ActualWidth < containerSize && Math.Abs(m_textBlock.FontSize - MaxFontSize) > FONTTOLERANCE && !m_haveCalculatedMax) + { + ModifyFontAndMargin(m_textBlock, fontSizeChange); + m_textBlock.InvalidateArrange(); + return; + } + if (fontSizeChange < 5) + { + m_haveCalculatedMax = true; + } + if (m_textBlock.ActualWidth >= containerSize && Math.Abs(m_textBlock.FontSize - MinFontSize) > FONTTOLERANCE) + { + ModifyFontAndMargin(m_textBlock, -1 * fontSizeChange); + m_textBlock.InvalidateArrange(); + return; + } + System.Diagnostics.Debug.Assert(m_textBlock.FontSize >= MinFontSize && m_textBlock.FontSize <= MaxFontSize); + m_isScalingText = false; + if (IsOperatorCommand) + { + m_textContainer.ChangeView(0.0, null, null); + } + else + { + m_textContainer.ChangeView(m_textContainer.ExtentWidth - m_textContainer.ViewportWidth, null, null); + } + + if (m_scrollLeft != null && m_scrollRight != null) + { + if (m_textBlock.ActualWidth < containerSize) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Collapsed); + } + else + { + if (IsOperatorCommand) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Visible); + } + else + { + ShowHideScrollButtons(Visibility.Visible, Visibility.Collapsed); + } + } + } + m_textBlock.InvalidateArrange(); + } + } + + void ScrollLeft() + { + if (m_textContainer.HorizontalOffset > 0) + { + double offset = m_textContainer.HorizontalOffset - (scrollRatio * m_textContainer.ViewportWidth); + m_textContainer.ChangeView(offset, null, null); + m_textContainer.UpdateLayout(); + UpdateScrollButtons(); + } + } + + void ScrollRight() + { + if (m_textContainer.HorizontalOffset < m_textContainer.ExtentWidth - m_textContainer.ViewportWidth) + { + double offset = m_textContainer.HorizontalOffset + (scrollRatio * m_textContainer.ViewportWidth); + m_textContainer.ChangeView(offset, null, null); + m_textContainer.UpdateLayout(); + UpdateScrollButtons(); + } + } + + void OnKeyDown(KeyRoutedEventArgs e) + { + if (m_scrollLeft != null && m_scrollRight != null) + { + var key = e.Key; + if (key == Windows.System.VirtualKey.Left) + { + this.ScrollLeft(); + } + else if (key == Windows.System.VirtualKey.Right) + { + this.ScrollRight(); + } + } + } + + void OnScrollClick(object sender, RoutedEventArgs e) + { + var clicked = (HyperlinkButton)(sender); + if (clicked == m_scrollLeft) + { + this.ScrollLeft(); + } + else + { + this.ScrollRight(); + } + } + + void OnPointerEntered(object sender, PointerRoutedEventArgs e) + { + if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse && m_textBlock.ActualWidth >= m_textContainer.ActualWidth) + { + UpdateScrollButtons(); + } + } + + void ShowHideScrollButtons(Visibility vLeft, Visibility vRight) + { + m_scrollLeft.Visibility = vLeft; + m_scrollRight.Visibility = vRight; + } + + void UpdateScrollButtons() + { + // When the width is smaller than the container, don't show any + if (m_textBlock.ActualWidth < m_textContainer.ActualWidth) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Collapsed); + } + // We have more number on both side. Show both arrows + else if (m_textContainer.HorizontalOffset > 0 && m_textContainer.HorizontalOffset < (m_textContainer.ExtentWidth - m_textContainer.ViewportWidth)) + { + ShowHideScrollButtons(Visibility.Visible, Visibility.Visible); + } + // Width is larger than the container and left most part of the number is shown. Should be able to scroll left. + else if (m_textContainer.HorizontalOffset == 0) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Visible); + } + else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left. + { + ShowHideScrollButtons(Visibility.Visible, Visibility.Collapsed); + } + } + + void OnPointerExited(object sender, PointerRoutedEventArgs e) + { + if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse) + { + UpdateScrollButtons(); + } + } + + void ModifyFontAndMargin(TextBlock textBox, double fontChange) + { + double cur = textBox.FontSize; + double newFontSize = 0.0; + double scaleFactor = SCALEFACTOR; + if (m_textContainer.ActualHeight <= HEIGHTCUTOFF) + { + scaleFactor = SMALLHEIGHTSCALEFACTOR; + } + + newFontSize = Math.Min(Math.Max(cur + fontChange, MinFontSize), MaxFontSize); + m_textContainer.Padding = new Thickness(0, 0, 0, scaleFactor * Math.Abs(cur - newFontSize)); + textBox.FontSize = newFontSize; + } + + void UpdateAllState() + { + UpdateVisualState(); + UpdateTextState(); + } + + protected override void OnTapped(TappedRoutedEventArgs e) + { + this.Focus(FocusState.Programmatic); + RaiseSelectedEvent(); + } + + protected override void OnRightTapped(RightTappedRoutedEventArgs e) + { + this.Focus(FocusState.Programmatic); + } + + protected override void OnGotFocus(RoutedEventArgs e) + { + if (this.FocusState == FocusState.Keyboard) + { + VisualStateManager.GoToState(this, s_FocusedState, true); + } + } + + protected override void OnLostFocus(RoutedEventArgs e) + { + VisualStateManager.GoToState(this, s_UnfocusedState, true); + } + + protected override AutomationPeer OnCreateAutomationPeer() + { + return new CalculationResultAutomationPeer(this); + } + + void ProgrammaticSelect() + { + RaiseSelectedEvent(); + } + + void RaiseSelectedEvent() + { + Selected?.Invoke(this); + } + }; + } +} diff --git a/src/Calculator.Shared/Controls/CalculationResultAutomationPeer.cs b/src/Calculator.Shared/Controls/CalculationResultAutomationPeer.cs new file mode 100644 index 00000000..2e9542b1 --- /dev/null +++ b/src/Calculator.Shared/Controls/CalculationResultAutomationPeer.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Automation.Provider; + +namespace CalculatorApp +{ + sealed class CalculationResultAutomationPeer : FrameworkElementAutomationPeer /* UNO TODO , IInvokeProvider*/ + { + public CalculationResultAutomationPeer(FrameworkElement owner) : base(owner) + { + + } + + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.Text; + } + + // UNO TODO + //override virtual object GetPatternCore(PatternInterface pattern) + //{ + // if (pattern == PatternInterface.Invoke) + // { + // return this; + // } + + // return FrameworkElementAutomationPeer.GetPatternCore(pattern); + //} + + // virtual void Invoke() + //{ + // var owner = Owner as CalculationResult; + // owner.ProgrammaticSelect(); + //} + } +} diff --git a/src/Calculator.Shared/Controls/CalculatorButton.cs b/src/Calculator.Shared/Controls/CalculatorButton.cs new file mode 100644 index 00000000..669e7e32 --- /dev/null +++ b/src/Calculator.Shared/Controls/CalculatorButton.cs @@ -0,0 +1,132 @@ +using CalculatorApp.Common; +using System; +using System.Collections.Generic; +using System.Text; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Controls +{ + public partial class CalculatorButton : Button + { + public CalculatorButton() + { + // Set the default bindings for this button, these can be overwritten by Xaml if needed + // These are a replacement for binding in styles + Binding commandBinding = new Binding(); + commandBinding.Path = new PropertyPath("ButtonPressed"); + this.SetBinding(Button.CommandProperty, commandBinding); + } + + // ButtonId + public NumbersAndOperatorsEnum ButtonId + { + get { return (NumbersAndOperatorsEnum)GetValue(ButtonIdProperty); } + set { SetValue(ButtonIdProperty, value); } + } + + public static readonly DependencyProperty ButtonIdProperty = + DependencyProperty.Register( + "ButtonId", + typeof(NumbersAndOperatorsEnum), + typeof(CalculatorButton), + new PropertyMetadata( + null, + (s, e) => (s as CalculatorButton)?.OnButtonIdPropertyChanged( + (NumbersAndOperatorsEnum)(e.OldValue ?? NumbersAndOperatorsEnum.None), + (NumbersAndOperatorsEnum)(e.NewValue ?? NumbersAndOperatorsEnum.None) + ) + ) + ); + + // AuditoryFeedback + public string AuditoryFeedback + { + get { return (string)GetValue(AuditoryFeedbackProperty); } + set { SetValue(AuditoryFeedbackProperty, value); } + } + + public static readonly DependencyProperty AuditoryFeedbackProperty = + DependencyProperty.Register("AuditoryFeedback", typeof(string), typeof(CalculatorButton), new PropertyMetadata(null)); + + // HoverBackground + public Brush HoverBackground + { + get { return (Brush)GetValue(HoverBackgroundProperty); } + set { SetValue(HoverBackgroundProperty, value); } + } + + public static readonly DependencyProperty HoverBackgroundProperty = + DependencyProperty.Register("HoverBackground", typeof(Brush), typeof(CalculatorButton), new PropertyMetadata(null)); + + // HoverForeground + public Brush HoverForeground + { + get { return (Brush)GetValue(HoverForegroundProperty); } + set { SetValue(HoverForegroundProperty, value); } + } + + public static readonly DependencyProperty HoverForegroundProperty = + DependencyProperty.Register("HoverForeground", typeof(Brush), typeof(CalculatorButton), new PropertyMetadata(null)); + + // PressBackground + public Brush PressBackground + { + get { return (Brush)GetValue(PressBackgroundProperty); } + set { SetValue(PressBackgroundProperty, value); } + } + + public static readonly DependencyProperty PressBackgroundProperty = + DependencyProperty.Register("PressBackground", typeof(Brush), typeof(CalculatorButton), new PropertyMetadata(null)); + + // PressForeground + public Brush PressForeground + { + get { return (Brush)GetValue(PressForegroundProperty); } + set { SetValue(PressBackgroundProperty, value); } + } + + public static readonly DependencyProperty PressForegroundProperty = + DependencyProperty.Register("PressForeground", typeof(Brush), typeof(CalculatorButton), new PropertyMetadata(null)); + + // PROTECTED + + protected override void OnKeyDown(KeyRoutedEventArgs e) + { + // Ignore the Enter key + if (e.Key == VirtualKey.Enter) + { + return; + } + + base.OnKeyDown(e); + } + + protected override void OnKeyUp(KeyRoutedEventArgs e) + { + // Ignore the Enter key + if (e.Key == VirtualKey.Enter) + { + return; + } + + base.OnKeyUp(e); + } + + // PRIVATE + + private void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue) + { + this.CommandParameter = new CalculatorButtonPressedEventArgs(AuditoryFeedback, newValue); + } + + private void OnAuditoryFeedbackPropertyChanged(string oldValue, string newValue) + { + this.CommandParameter = new CalculatorButtonPressedEventArgs(newValue, ButtonId); + } + } +} diff --git a/src/Calculator.Shared/Controls/FlipButtons.cs b/src/Calculator.Shared/Controls/FlipButtons.cs new file mode 100644 index 00000000..ea6f8373 --- /dev/null +++ b/src/Calculator.Shared/Controls/FlipButtons.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Controls +{ + public partial class FlipButtons : ToggleButton + { + + // NumbersAndOperatorsEnum + public NumbersAndOperatorsEnum ButtonId + { + get { return (NumbersAndOperatorsEnum)GetValue(ButtonIdProperty); } + set { SetValue(ButtonIdProperty, value); } + } + + public static readonly DependencyProperty ButtonIdProperty = + DependencyProperty.Register("ButtonId", typeof(NumbersAndOperatorsEnum), typeof(FlipButtons), new PropertyMetadata(null)); + + // HoverBackground + public Brush HoverBackground + { + get { return (Brush)GetValue(HoverBackgroundProperty); } + set { SetValue(HoverBackgroundProperty, value); } + } + + public static readonly DependencyProperty HoverBackgroundProperty = + DependencyProperty.Register("HoverBackground", typeof(Brush), typeof(FlipButtons), new PropertyMetadata(null)); + + // HoverForeground + public Brush HoverForeground + { + get { return (Brush)GetValue(HoverForegroundProperty); } + set { SetValue(HoverForegroundProperty, value); } + } + + public static readonly DependencyProperty HoverForegroundProperty = + DependencyProperty.Register("HoverForeground", typeof(Brush), typeof(FlipButtons), new PropertyMetadata(null)); + + // PressBackground + public Brush PressBackground + { + get { return (Brush)GetValue(PressBackgroundProperty); } + set { SetValue(PressBackgroundProperty, value); } + } + + public static readonly DependencyProperty PressBackgroundProperty = + DependencyProperty.Register("PressBackground", typeof(Brush), typeof(FlipButtons), new PropertyMetadata(null)); + + // PressForeground + public Brush PressForeground + { + get { return (Brush)GetValue(PressForegroundProperty); } + set { SetValue(PressForegroundProperty, value); } + } + + public static readonly DependencyProperty PressForegroundProperty = + DependencyProperty.Register("PressForeground", typeof(Brush), typeof(FlipButtons), new PropertyMetadata(null)); + + // PROTECTED + override protected void OnKeyDown(KeyRoutedEventArgs e) + { + // Ignore the Enter key + if (e.Key == VirtualKey.Enter) + { + return; + } + + base.OnKeyDown(e); + } + + override protected void OnKeyUp(KeyRoutedEventArgs e) + { + // Ignore the Enter key + if (e.Key == VirtualKey.Enter) + { + return; + } + + base.OnKeyUp(e); + } + + // PRIVATE + private void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue) + { + this.CommandParameter = newValue; + } + } +} diff --git a/src/Calculator.Shared/Controls/KeyboardShortcutManager.cs b/src/Calculator.Shared/Controls/KeyboardShortcutManager.cs new file mode 100644 index 00000000..d16a97c8 --- /dev/null +++ b/src/Calculator.Shared/Controls/KeyboardShortcutManager.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + + +using Windows.UI.Xaml; + +namespace CalculatorApp +{ + namespace Common + { + public static class KeyboardShortcutManager + { + public static string GetCharacter(DependencyObject obj) => (string)obj.GetValue(CharacterProperty); + + public static void SetCharacter(DependencyObject obj, string value) => obj.SetValue(CharacterProperty, value); + + // Using a DependencyProperty as the backing store for Character. This enables animation, styling, binding, etc... + public static readonly DependencyProperty CharacterProperty = + DependencyProperty.RegisterAttached("Character", typeof(string), typeof(KeyboardShortcutManager), new PropertyMetadata("")); + + + public static MyVirtualKey GetVirtualKey(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyProperty); + + public static void SetVirtualKey(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKey. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyProperty = + DependencyProperty.RegisterAttached("VirtualKey", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + + + + + public static MyVirtualKey GetVirtualKeyControlChord(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyControlChordProperty); + + public static void SetVirtualKeyControlChord(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyControlChordProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKeyControlChord. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyControlChordProperty = + DependencyProperty.RegisterAttached("VirtualKeyControlChord", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + + + + + public static MyVirtualKey GetVirtualKeyShiftChord(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyShiftChordProperty); + + public static void SetVirtualKeyShiftChord(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyShiftChordProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKeyShiftChord. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyShiftChordProperty = + DependencyProperty.RegisterAttached("VirtualKeyShiftChord", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + + + + + public static MyVirtualKey GetVirtualKeyAltChord(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyAltChordProperty); + + public static void SetVirtualKeyAltChord(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyAltChordProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKeyAltChord. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyAltChordProperty = + DependencyProperty.RegisterAttached("VirtualKeyAltChord", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + + + + + public static MyVirtualKey GetVirtualKeyControlShiftChord(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyControlShiftChordProperty); + + public static void SetVirtualKeyControlShiftChord(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyControlShiftChordProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKeyControlShiftChord. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyControlShiftChordProperty = + DependencyProperty.RegisterAttached("VirtualKeyControlShiftChord", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + + + + + public static MyVirtualKey GetVirtualKeyInverseChord(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyInverseChordProperty); + + public static void SetVirtualKeyInverseChord(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyInverseChordProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKeyInverseChord. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyInverseChordProperty = + DependencyProperty.RegisterAttached("VirtualKeyInverseChord", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + + + + public static MyVirtualKey GetVirtualKeyControlInverseChord(DependencyObject obj) => (MyVirtualKey)obj.GetValue(VirtualKeyControlInverseChordProperty); + + public static void SetVirtualKeyControlInverseChord(DependencyObject obj, MyVirtualKey value) => obj.SetValue(VirtualKeyControlInverseChordProperty, value); + + // Using a DependencyProperty as the backing store for VirtualKeyControlInverseChord. This enables animation, styling, binding, etc... + public static readonly DependencyProperty VirtualKeyControlInverseChordProperty = + DependencyProperty.RegisterAttached("VirtualKeyControlInverseChord", typeof(MyVirtualKey), typeof(KeyboardShortcutManager), new PropertyMetadata(MyVirtualKey.None)); + } + } +} diff --git a/src/Calculator.Shared/Controls/OperandTextBox.cs b/src/Calculator.Shared/Controls/OperandTextBox.cs new file mode 100644 index 00000000..e7c46e6a --- /dev/null +++ b/src/Calculator.Shared/Controls/OperandTextBox.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + + +namespace CalculatorApp.Controls +{ + partial class OperandTextBox : TextBox + { + protected override void OnApplyTemplate() + { + this.IsEnabled = false; + this.IsHitTestVisible = false; + this.IsTapEnabled = false; + this.MaxLength = 50; + this.IsRightTapEnabled = false; + this.IsTabStop = false; + var parent = VisualTreeHelper.GetParent(this); + + ListViewItem listViewItem = null; + ListView listView = null; + + while (parent != null) + { + if (listViewItem == null) + { + listViewItem = parent as ListViewItem; + } + + listView = parent as ListView; + if (listView != null) + { + break; + } + parent = VisualTreeHelper.GetParent(parent); + } + + if (listView != null) + { + listViewItem.IsEnabled = false; + listViewItem.IsHitTestVisible = false; + listViewItem.IsTapEnabled = false; + } + + base.OnApplyTemplate(); + } + } +} diff --git a/src/Calculator.Shared/Controls/OperatorTextBox.cs b/src/Calculator.Shared/Controls/OperatorTextBox.cs new file mode 100644 index 00000000..a4ece40c --- /dev/null +++ b/src/Calculator.Shared/Controls/OperatorTextBox.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Controls +{ + partial class OperatorTextBox : TextBox + { + + protected override void OnApplyTemplate() + { + this.IsEnabled = false; + this.IsHitTestVisible = false; + this.IsTapEnabled = false; + this.MaxLength = 50; + this.IsReadOnly = true; + this.IsRightTapEnabled = false; + this.IsTabStop = false; + + var parent = VisualTreeHelper.GetParent(this); + + ListViewItem listViewItem = null; + ListView listView = null; + + while (parent != null) + { + if (listViewItem == null) + { + listViewItem = parent as ListViewItem; + } + + listView = parent as ListView; + if (listView != null) + { + break; + } + parent = VisualTreeHelper.GetParent(parent); + } + + if (listView != null) + { + listViewItem.IsEnabled = false; + listViewItem.IsHitTestVisible = false; + listViewItem.IsTapEnabled = false; + } + + base.OnApplyTemplate(); + } + } +} diff --git a/src/Calculator.Shared/Controls/OverflowTextBlock.cs b/src/Calculator.Shared/Controls/OverflowTextBlock.cs new file mode 100644 index 00000000..c2f48218 --- /dev/null +++ b/src/Calculator.Shared/Controls/OverflowTextBlock.cs @@ -0,0 +1,268 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Text; +using Windows.Devices.Input; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Controls +{ + public partial class OverflowTextBlock : Control + { + const double scrollRatio = 0.7; + + bool m_scrollingLeft; + bool m_scrollingRight; + + ListView m_listView; + ScrollViewer m_expressionContainer; + Button m_scrollLeft; + Button m_scrollRight; + + EventRegistrationToken m_scrollLeftClickEventToken; + EventRegistrationToken m_scrollRightClickEventToken; + EventRegistrationToken m_pointerEnteredEventToken; + EventRegistrationToken m_pointerExitedEventToken; + private ItemsControl m_itemsControl; + private bool m_isAccessibilityViewControl; + + + + public bool TokensUpdated + { + get { return (bool)GetValue(TokensUpdatedProperty); } + set { SetValue(TokensUpdatedProperty, value); } + } + + public static readonly DependencyProperty TokensUpdatedProperty = + DependencyProperty.Register("TokensUpdated", typeof(bool), typeof(OverflowTextBlock), new PropertyMetadata(false)); + + + + public bool IsActive + { + get { return (bool)GetValue(IsActiveProperty); } + set { SetValue(IsActiveProperty, value); } + } + + public static readonly DependencyProperty IsActiveProperty = + DependencyProperty.Register("IsActive", typeof(bool), typeof(OverflowTextBlock), new PropertyMetadata(false)); + + + + public Style TextStyle + { + get { return (Style)GetValue(TextStyleProperty); } + set { SetValue(TextStyleProperty, value); } + } + + public static readonly DependencyProperty TextStyleProperty = + DependencyProperty.Register("TextStyle", typeof(Style), typeof(OverflowTextBlock), new PropertyMetadata(null)); + + + protected override void OnApplyTemplate() + { + UnregisterEventHandlers(); + + var uiElement = GetTemplateChild("ExpressionContainer"); + if (uiElement != null) + { + m_expressionContainer = uiElement as ScrollViewer; + m_expressionContainer.ChangeView(m_expressionContainer.ExtentWidth - m_expressionContainer.ViewportWidth, null, null); + m_expressionContainer.ViewChanged += OnViewChanged; + } + + uiElement = GetTemplateChild("ScrollLeft"); + if (uiElement != null) + { + m_scrollLeft = (uiElement as Button); + m_scrollLeft.Click += OnScrollClick; + } + + uiElement = GetTemplateChild("ScrollRight"); + if (uiElement != null) + { + m_scrollRight = (uiElement as Button); + m_scrollRight.Click += OnScrollClick; + } + + m_scrollingLeft = false; + m_scrollingRight = false; + + uiElement = GetTemplateChild("TokenList"); + if (uiElement != null) + { + m_itemsControl = (uiElement as ItemsControl); + } + + UpdateAllState(); + } + + AutomationPeer OnCreateAutomationPeer() + { + return new OverflowTextBlockAutomationPeer(this); + } + + void OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue) + { + if (m_expressionContainer != null && newValue) + { + m_expressionContainer.UpdateLayout(); + m_expressionContainer.ChangeView(m_expressionContainer.ScrollableWidth, null, null, true); + } + var newIsAccessibilityViewControl = m_itemsControl != null && m_itemsControl.Items.Count > 0; + if (m_isAccessibilityViewControl != newIsAccessibilityViewControl) + { + m_isAccessibilityViewControl = newIsAccessibilityViewControl; + AutomationProperties.SetAccessibilityView(this, newIsAccessibilityViewControl ? AccessibilityView.Control : AccessibilityView.Raw); + } + UpdateScrollButtons(); + } + + void UpdateAllState() + { + UpdateVisualState(); + } + + void UpdateVisualState() + { + if (IsActive) + { + VisualStateManager.GoToState(this, "Active", true); + } + else + { + VisualStateManager.GoToState(this, "Normal", true); + } + } + + void ScrollLeft() + { + if (m_expressionContainer != null && m_expressionContainer.HorizontalOffset > 0) + { + m_scrollingLeft = true; + double offset = m_expressionContainer.HorizontalOffset - (scrollRatio * m_expressionContainer.ViewportWidth); + m_expressionContainer.ChangeView(offset, null, null); + m_expressionContainer.UpdateLayout(); + UpdateScrollButtons(); + } + } + + void ScrollRight() + { + if (m_expressionContainer != null && m_expressionContainer.HorizontalOffset < m_expressionContainer.ExtentWidth - m_expressionContainer.ViewportWidth) + { + m_scrollingRight = true; + double offset = m_expressionContainer.HorizontalOffset + (scrollRatio * m_expressionContainer.ViewportWidth); + m_expressionContainer.ChangeView(offset, null, null); + m_expressionContainer.UpdateLayout(); + UpdateScrollButtons(); + } + } + + void OnScrollClick(object sender, RoutedEventArgs args) + { + var clicked = (sender as Button); + if (clicked == m_scrollLeft) + { + ScrollLeft(); + } + else + { + ScrollRight(); + } + } + + void UpdateScrollButtons() + { + if (m_itemsControl == null || m_expressionContainer == null) + { + return; + } + + // When the width is smaller than the container, don't show any + if (m_itemsControl.ActualWidth <= m_expressionContainer.ActualWidth) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Collapsed); + } + // We have more number on both side. Show both arrows + else if ( + (m_expressionContainer.HorizontalOffset > 0) + && (m_expressionContainer.HorizontalOffset < (m_expressionContainer.ExtentWidth - m_expressionContainer.ViewportWidth))) + { + ShowHideScrollButtons(Visibility.Visible, Visibility.Visible); + } + // Width is larger than the container and left most part of the number is shown. Should be able to scroll left. + else if (m_expressionContainer.HorizontalOffset == 0) + { + ShowHideScrollButtons(Visibility.Collapsed, Visibility.Visible); + if (m_scrollingLeft) + { + m_scrollingLeft = false; + if (m_scrollRight != null) + { + m_scrollRight.Focus(FocusState.Programmatic); + } + } + } + else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left. + { + ShowHideScrollButtons(Visibility.Visible, Visibility.Collapsed); + if (m_scrollingRight) + { + m_scrollingRight = false; + if (m_scrollLeft != null) + { + m_scrollLeft.Focus(FocusState.Programmatic); + } + } + } + } + + void ShowHideScrollButtons(Visibility vLeft, Visibility vRight) + { + if (m_scrollLeft != null && m_scrollRight != null) + { + m_scrollLeft.Visibility = vLeft; + m_scrollRight.Visibility = vRight; + } + } + + public void UnregisterEventHandlers() + { + // UNO TODO Unregister + + // Unregister the event handlers + //if (m_scrollLeft != null) + //{ + // m_scrollLeft.Click -= m_scrollLeftClickEventToken; + //} + + //if (m_scrollRight != null) + //{ + // m_scrollRight.Click -= m_scrollRightClickEventToken; + //} + + //if (m_expressionContainer != null) + //{ + // m_expressionContainer.ViewChanged -= m_containerViewChangedToken; + //} + } + + void OnViewChanged(object sender, ScrollViewerViewChangedEventArgs args) + { + UpdateScrollButtons(); + } + + } +} diff --git a/src/Calculator.Shared/Controls/OverflowTextBlockAutomationPeer.cs b/src/Calculator.Shared/Controls/OverflowTextBlockAutomationPeer.cs new file mode 100644 index 00000000..33c505ea --- /dev/null +++ b/src/Calculator.Shared/Controls/OverflowTextBlockAutomationPeer.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Text; +using Windows.Devices.Input; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Controls +{ + sealed class OverflowTextBlockAutomationPeer : FrameworkElementAutomationPeer + { + public OverflowTextBlockAutomationPeer(OverflowTextBlock owner) : + base(owner) + { } + + override protected AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.Text; + } + + override protected IList GetChildrenCore() + { + return null; + } + } +} diff --git a/src/Calculator.Shared/Controls/RadixButton.cs b/src/Calculator.Shared/Controls/RadixButton.cs new file mode 100644 index 00000000..d3e270ab --- /dev/null +++ b/src/Calculator.Shared/Controls/RadixButton.cs @@ -0,0 +1,30 @@ +using CalculatorApp.Common; +using System; +using System.Collections.Generic; +using System.Text; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; + +namespace CalculatorApp.Controls +{ + public partial class RadixButton : RadioButton + { + public RadixButton() + { + + } + + internal string GetRawDisplayValue() + { + string rawValue = null; + string radixContent = Content.ToString(); + LocalizationSettings.GetInstance().RemoveGroupSeparators(radixContent, radixContent.Length, ref rawValue); + + return rawValue; + } + } +} diff --git a/src/Calculator.Shared/Controls/SupplementaryItemsControl.cs b/src/Calculator.Shared/Controls/SupplementaryItemsControl.cs new file mode 100644 index 00000000..a4b9adbb --- /dev/null +++ b/src/Calculator.Shared/Controls/SupplementaryItemsControl.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Controls; + +namespace CalculatorApp.Controls +{ + public partial class SupplementaryItemsControl : ItemsControl + { + // PROTECTED + protected override DependencyObject GetContainerForItemOverride() + { + return new SupplementaryContentPresenter(); + } + + protected override void PrepareContainerForItemOverride(DependencyObject element, Object item) + { + base.PrepareContainerForItemOverride(element, item); + + // UNO TODO + //var supplementaryResult = (SupplementaryResult)(item); + //if (supplementaryResult) + //{ + // AutomationProperties.SetName(element, supplementaryResult.GetLocalizedAutomationName()); + //} + } + } + + public sealed partial class SupplementaryContentPresenter : ContentPresenter + { + + protected override AutomationPeer OnCreateAutomationPeer() + { + return null; + } + } + + public sealed partial class SupplementaryContentPresenterAP : FrameworkElementAutomationPeer + { + protected override AutomationControlType GetAutomationControlTypeCore() + { + return AutomationControlType.Text; + } + + protected override IList GetChildrenCore() + { + return null; + } + + internal SupplementaryContentPresenterAP(SupplementaryContentPresenter owner) : + base(owner) + { + } + } +} diff --git a/src/Calculator.Shared/Converters/AlwaysSelectedCollectionViewConverter.cs b/src/Calculator.Shared/Converters/AlwaysSelectedCollectionViewConverter.cs new file mode 100644 index 00000000..5be2b44a --- /dev/null +++ b/src/Calculator.Shared/Converters/AlwaysSelectedCollectionViewConverter.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculatorApp +{ + namespace Common + { + //class AlwaysSelectedCollectionViewConverter : Windows.UI.Xaml.Data.IValueConverter + //{ + // public AlwaysSelectedCollectionViewConverter() + // { + // } + + // object Convert( + // object value, + // Type targetType, + // object parameter, + // string language) + // { + // var result = (IEnumerable)(value); + // if (result) + // { + // return new AlwaysSelectedCollectionView(result); + // } + // return Windows.UI.Xaml.DependencyProperty.UnsetValue; // Can't convert + // } + + // object ConvertBack( + // object value, + // Type targetType, + // object parameter, + // string language) + // { + // return Windows.UI.Xaml.DependencyProperty.UnsetValue; + // } + //} + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/Converters/BitFlipAutomationNameConverter.cs b/src/Calculator.Shared/Converters/BitFlipAutomationNameConverter.cs new file mode 100644 index 00000000..59d3ba0f --- /dev/null +++ b/src/Calculator.Shared/Converters/BitFlipAutomationNameConverter.cs @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp.Common; +using System; +using System.Text; + +namespace CalculatorApp +{ + namespace Converters + { + /// + /// Value converter that translates binary value to automation name for a bit. + /// + public class BitFlipAutomationNameConverter : Windows.UI.Xaml.Data.IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + var resourceLoader = AppResourceProvider.GetInstance(); + + // initialising the updated display with 64 bits of zeros + char[] updatedBinaryDisplay = new char[64]; + + var localizationSettings = LocalizationSettings.GetInstance(); + char ch0 = localizationSettings.GetDigitSymbolFromEnUsDigit('0'); + char ch1 = localizationSettings.GetDigitSymbolFromEnUsDigit('1'); + + string indexName = resourceLoader.GetResourceString((string)(parameter)); + string bitName = resourceLoader.GetResourceString("BitAutomationName"); + string valueName = resourceLoader.GetResourceString("ValueAutomationName"); + string zero = resourceLoader.GetResourceString("BinaryZeroValueAutomationName"); + string one = resourceLoader.GetResourceString("BinaryOneValueAutomationName"); + if ((value != null) && (parameter != null)) + { + string binaryDisplay = (string)value; + string indexString = (string)parameter; + int index = int.Parse(indexString); + int binaryLength = 0; + + // remove all the characters except 0 and 1 from the array. + foreach (char bit in binaryDisplay) + { + if ((bit == ch1) || (bit == ch0)) + { + updatedBinaryDisplay[binaryLength++] = bit; + } + if (binaryLength == 63) + { + break; + } + } + + // return if binaryDisplay is empty + if (binaryLength == 0) + { + return (indexName + bitName + valueName + zero); + } + + // if index is more than the length of binary display return automation name with zero + if (index >= binaryLength) + { + return (indexName + bitName + valueName + zero); + } + // if bit is set return automation name with one else return zero + if (updatedBinaryDisplay[binaryLength - index - 1] == ch1) + { + return (indexName + bitName + valueName + one); + } + } + return (indexName + bitName + valueName + zero); + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + return value; + } + + } + } +} diff --git a/src/Calculator.Shared/Converters/BooleanNegationConverter.cs b/src/Calculator.Shared/Converters/BooleanNegationConverter.cs new file mode 100644 index 00000000..0fe17ab6 --- /dev/null +++ b/src/Calculator.Shared/Converters/BooleanNegationConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Data; + +namespace CalculatorApp.Converters +{ + class BooleanNegationConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string culture) + { + bool? boxedBool = value as bool?; + + if (boxedBool != null) + { + return !boxedBool; + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, string culture) + { + return value; + } + } +} diff --git a/src/Calculator.Shared/Converters/BooleanToVisibilityConverter.cs b/src/Calculator.Shared/Converters/BooleanToVisibilityConverter.cs new file mode 100644 index 00000000..aef26294 --- /dev/null +++ b/src/Calculator.Shared/Converters/BooleanToVisibilityConverter.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Data; + +namespace CalculatorApp.Converters +{ + public class BooleanToVisibilityConverter : IValueConverter + { + public static Visibility Convert(bool visibility) + { + return visibility ? Windows.UI.Xaml.Visibility.Visible : Windows.UI.Xaml.Visibility.Collapsed; + } + + public object Convert(object value, Type targetType, object parameter, string culture) + { + bool? boxedBool = value as bool?; + + if (boxedBool != null) + { + return boxedBool.Value ? Visibility.Visible : Visibility.Collapsed; + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, string culture) + { + return value; + } + } + + public class BooleanToVisibilityNegationConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string culture) + { + bool? boxedBool = value as bool?; + + if (boxedBool != null) + { + return boxedBool.Value ? Visibility.Collapsed : Visibility.Visible; + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, string culture) + { + return value; + } + } +} diff --git a/src/Calculator.Shared/Converters/DelighterUnitToSyleConverter.cs b/src/Calculator.Shared/Converters/DelighterUnitToSyleConverter.cs new file mode 100644 index 00000000..baa6bbfc --- /dev/null +++ b/src/Calculator.Shared/Converters/DelighterUnitToSyleConverter.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// +// SupplementaryResults.xaml.h +// Declaration of the SupplementaryResults class +// + +using System; +using System.Diagnostics; + +namespace CalculatorApp +{ + //public class DelighterUnitToStyleConverter : Windows.UI.Xaml.Data.IValueConverter + //{ + // DelighterUnitToStyleConverter() + // { + // m_delighters = new Windows.UI.Xaml.ResourceDictionary(); + // m_delighters.Source = new Uri("ms-appx:///Views/DelighterUnitStyles.xaml"); + // } + + // Windows.UI.Xaml.ResourceDictionary m_delighters; + + // public object Convert(object value, Type targetType, object parameter, String language) + // { + // Unit unit = (Unit)(value); + + // Debug.Assert(unit.GetModelUnit().isWhimsical); + // if (!unit.GetModelUnit().isWhimsical) + // { + // return null; + // } + + // std.string key = "Unit_"; + // key.append(std.to_wstring(unit.GetModelUnit().id)); + // return IStyle > (m_delighters.Lookup(new String(key.c_str()))); + // } + + // public object ConvertBack(object value, Type targetType, object parameter, String language) + // { + // // We never use convert back, only one way binding supported + // Debug.Assert(false); + // return null; + // } + + //}; +} \ No newline at end of file diff --git a/src/Calculator.Shared/Converters/ExpressionItemContainerStyle.cs b/src/Calculator.Shared/Converters/ExpressionItemContainerStyle.cs new file mode 100644 index 00000000..af429c4f --- /dev/null +++ b/src/Calculator.Shared/Converters/ExpressionItemContainerStyle.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculatorApp.Converters +{ + //class ExpressionItemContainerStyle : ConverterBase + //{ + // protected override object Convert(object value, Type targetType, object parameter) + // { + // return value; + // } + + // protected override object ConvertBack(object value, Type targetType, object parameter) + // { + // return value; + // } + //} +} diff --git a/src/Calculator.Shared/Converters/ExpressionItemTemplateSelector.cs b/src/Calculator.Shared/Converters/ExpressionItemTemplateSelector.cs new file mode 100644 index 00000000..c1e56077 --- /dev/null +++ b/src/Calculator.Shared/Converters/ExpressionItemTemplateSelector.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp.Common; +using System; + +namespace CalculatorApp +{ + namespace Converters + { + [Windows.UI.Xaml.Data.Bindable] + public sealed class ExpressionItemTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector + { + Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, Windows.UI.Xaml.DependencyObject container) + { + DisplayExpressionToken token = (DisplayExpressionToken)(item); + if (token != null) + { + Common.TokenType type = token.Type; + + switch (type) + { + case TokenType.Operator: + return m_operatorTemplate; + case TokenType.Operand: + return m_operandTemplate; + case TokenType.Separator: + return m_separatorTemplate; + default: + throw new Exception("Invalid token type"); + } + } + + return m_separatorTemplate; + } + + public Windows.UI.Xaml.DataTemplate OperatorTemplate + { + get => m_operatorTemplate; + set => m_operatorTemplate = value; + } + + public Windows.UI.Xaml.DataTemplate OperandTemplate + { + get => m_operandTemplate; + set => m_operandTemplate = value; + } + + public Windows.UI.Xaml.DataTemplate SeparatorTemplate + { + get => m_separatorTemplate; + set => m_separatorTemplate = value; + } + + private Windows.UI.Xaml.DataTemplate m_operatorTemplate; + private Windows.UI.Xaml.DataTemplate m_operandTemplate; + private Windows.UI.Xaml.DataTemplate m_separatorTemplate; + }; + } +} diff --git a/src/Calculator.Shared/Converters/ItemSizeToVisibilityConverter.cs b/src/Calculator.Shared/Converters/ItemSizeToVisibilityConverter.cs new file mode 100644 index 00000000..eb531504 --- /dev/null +++ b/src/Calculator.Shared/Converters/ItemSizeToVisibilityConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Interop; +using Windows.Foundation.Metadata; +using Windows.UI.Xaml.Data; + +namespace CalculatorApp.Converters +{ + sealed public class ItemSizeToVisibilityConverter : IValueConverter + { + public Object Convert(Object value, Type targetType, Object parameter, String language) + { + var items = (int)value; + var boolValue = items == 0; + + return BooleanToVisibilityConverter.Convert(boolValue); + } + + public object ConvertBack(Object value, Type targetType, Object parameter, String language) + { + throw new NotImplementedException(); + } + + } + + public class ItemSizeToVisibilityNegationConverter : IValueConverter + { + public Object Convert(Object value, Type targetType, Object parameter, String language) + { + var items = (int)value; + var boolValue = items > 0; + + return BooleanToVisibilityConverter.Convert(boolValue); + } + public Object ConvertBack(Object value, Type targetType, Object parameter, String language) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/Converters/RadixToStringConverter.cs b/src/Calculator.Shared/Converters/RadixToStringConverter.cs new file mode 100644 index 00000000..a14527f1 --- /dev/null +++ b/src/Calculator.Shared/Converters/RadixToStringConverter.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Interop; +using Windows.Foundation.Metadata; +using Windows.UI.Xaml.Data; +using CalculationManager; +using CalculatorApp; + +namespace CalculatorApp.Converters +{ + [WebHostHidden] + class RadixToStringConverter : IValueConverter + { + public object Convert(Object value, Type targetType, Object parameter, String language) + { + var boxedInt = (RADIX_TYPE)(int)value; + string convertedValue = ""; + var resourceLoader = AppResourceProvider.GetInstance(); + + switch (boxedInt) + { + case RADIX_TYPE.BIN_RADIX: + convertedValue = resourceLoader.GetResourceString("Bin"); + break; + case RADIX_TYPE.OCT_RADIX: + convertedValue = resourceLoader.GetResourceString("Oct"); + break; + case RADIX_TYPE.DEC_RADIX: + convertedValue = resourceLoader.GetResourceString("Dec"); + break; + case RADIX_TYPE.HEX_RADIX: + convertedValue = resourceLoader.GetResourceString("Hex"); + break; + default: + break; + + }; + + return convertedValue; + } + + public virtual object ConvertBack(Object value, Type targetType, Object parameter, String language) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/Converters/VisibilityNegationConverter.cs b/src/Calculator.Shared/Converters/VisibilityNegationConverter.cs new file mode 100644 index 00000000..59e829ec --- /dev/null +++ b/src/Calculator.Shared/Converters/VisibilityNegationConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Interop; +using Windows.Foundation.Metadata; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml; + +namespace CalculatorApp.Converters +{ + [WebHostHidden] + public sealed class VisibilityNegationConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, String language) + { + var boxedVisibility = (Visibility)value; + Visibility visibility = Visibility.Collapsed; + + if (boxedVisibility == Visibility.Collapsed) + { + visibility = Visibility.Visible; + } + + return visibility; + } + + public object ConvertBack(Object value, Type targetType, Object parameter, String language) + { + return Convert(value, targetType, parameter, language); + } + } +} diff --git a/src/Calculator/Resources/af-ZA/CEngineStrings.resw b/src/Calculator.Shared/Resources/af-ZA/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/af-ZA/CEngineStrings.resw rename to src/Calculator.Shared/Resources/af-ZA/CEngineStrings.resw diff --git a/src/Calculator/Resources/af-ZA/Resources.resw b/src/Calculator.Shared/Resources/af-ZA/Resources.resw similarity index 100% rename from src/Calculator/Resources/af-ZA/Resources.resw rename to src/Calculator.Shared/Resources/af-ZA/Resources.resw diff --git a/src/Calculator/Resources/am-ET/CEngineStrings.resw b/src/Calculator.Shared/Resources/am-ET/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/am-ET/CEngineStrings.resw rename to src/Calculator.Shared/Resources/am-ET/CEngineStrings.resw diff --git a/src/Calculator/Resources/am-ET/Resources.resw b/src/Calculator.Shared/Resources/am-ET/Resources.resw similarity index 100% rename from src/Calculator/Resources/am-ET/Resources.resw rename to src/Calculator.Shared/Resources/am-ET/Resources.resw diff --git a/src/Calculator/Resources/ar-SA/CEngineStrings.resw b/src/Calculator.Shared/Resources/ar-SA/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ar-SA/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ar-SA/CEngineStrings.resw diff --git a/src/Calculator/Resources/ar-SA/Resources.resw b/src/Calculator.Shared/Resources/ar-SA/Resources.resw similarity index 100% rename from src/Calculator/Resources/ar-SA/Resources.resw rename to src/Calculator.Shared/Resources/ar-SA/Resources.resw diff --git a/src/Calculator/Resources/az-Latn-AZ/CEngineStrings.resw b/src/Calculator.Shared/Resources/az-Latn-AZ/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/az-Latn-AZ/CEngineStrings.resw rename to src/Calculator.Shared/Resources/az-Latn-AZ/CEngineStrings.resw diff --git a/src/Calculator/Resources/az-Latn-AZ/Resources.resw b/src/Calculator.Shared/Resources/az-Latn-AZ/Resources.resw similarity index 100% rename from src/Calculator/Resources/az-Latn-AZ/Resources.resw rename to src/Calculator.Shared/Resources/az-Latn-AZ/Resources.resw diff --git a/src/Calculator/Resources/be-BY/CEngineStrings.resw b/src/Calculator.Shared/Resources/be-BY/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/be-BY/CEngineStrings.resw rename to src/Calculator.Shared/Resources/be-BY/CEngineStrings.resw diff --git a/src/Calculator/Resources/be-BY/Resources.resw b/src/Calculator.Shared/Resources/be-BY/Resources.resw similarity index 100% rename from src/Calculator/Resources/be-BY/Resources.resw rename to src/Calculator.Shared/Resources/be-BY/Resources.resw diff --git a/src/Calculator/Resources/bg-BG/CEngineStrings.resw b/src/Calculator.Shared/Resources/bg-BG/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/bg-BG/CEngineStrings.resw rename to src/Calculator.Shared/Resources/bg-BG/CEngineStrings.resw diff --git a/src/Calculator/Resources/bg-BG/Resources.resw b/src/Calculator.Shared/Resources/bg-BG/Resources.resw similarity index 100% rename from src/Calculator/Resources/bg-BG/Resources.resw rename to src/Calculator.Shared/Resources/bg-BG/Resources.resw diff --git a/src/Calculator/Resources/bn-BD/CEngineStrings.resw b/src/Calculator.Shared/Resources/bn-BD/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/bn-BD/CEngineStrings.resw rename to src/Calculator.Shared/Resources/bn-BD/CEngineStrings.resw diff --git a/src/Calculator/Resources/bn-BD/Resources.resw b/src/Calculator.Shared/Resources/bn-BD/Resources.resw similarity index 100% rename from src/Calculator/Resources/bn-BD/Resources.resw rename to src/Calculator.Shared/Resources/bn-BD/Resources.resw diff --git a/src/Calculator/Resources/ca-ES/CEngineStrings.resw b/src/Calculator.Shared/Resources/ca-ES/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ca-ES/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ca-ES/CEngineStrings.resw diff --git a/src/Calculator/Resources/ca-ES/Resources.resw b/src/Calculator.Shared/Resources/ca-ES/Resources.resw similarity index 100% rename from src/Calculator/Resources/ca-ES/Resources.resw rename to src/Calculator.Shared/Resources/ca-ES/Resources.resw diff --git a/src/Calculator/Resources/cs-CZ/CEngineStrings.resw b/src/Calculator.Shared/Resources/cs-CZ/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/cs-CZ/CEngineStrings.resw rename to src/Calculator.Shared/Resources/cs-CZ/CEngineStrings.resw diff --git a/src/Calculator/Resources/cs-CZ/Resources.resw b/src/Calculator.Shared/Resources/cs-CZ/Resources.resw similarity index 100% rename from src/Calculator/Resources/cs-CZ/Resources.resw rename to src/Calculator.Shared/Resources/cs-CZ/Resources.resw diff --git a/src/Calculator/Resources/da-DK/CEngineStrings.resw b/src/Calculator.Shared/Resources/da-DK/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/da-DK/CEngineStrings.resw rename to src/Calculator.Shared/Resources/da-DK/CEngineStrings.resw diff --git a/src/Calculator/Resources/da-DK/Resources.resw b/src/Calculator.Shared/Resources/da-DK/Resources.resw similarity index 100% rename from src/Calculator/Resources/da-DK/Resources.resw rename to src/Calculator.Shared/Resources/da-DK/Resources.resw diff --git a/src/Calculator/Resources/de-DE/CEngineStrings.resw b/src/Calculator.Shared/Resources/de-DE/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/de-DE/CEngineStrings.resw rename to src/Calculator.Shared/Resources/de-DE/CEngineStrings.resw diff --git a/src/Calculator/Resources/de-DE/Resources.resw b/src/Calculator.Shared/Resources/de-DE/Resources.resw similarity index 100% rename from src/Calculator/Resources/de-DE/Resources.resw rename to src/Calculator.Shared/Resources/de-DE/Resources.resw diff --git a/src/Calculator/Resources/el-GR/CEngineStrings.resw b/src/Calculator.Shared/Resources/el-GR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/el-GR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/el-GR/CEngineStrings.resw diff --git a/src/Calculator/Resources/el-GR/Resources.resw b/src/Calculator.Shared/Resources/el-GR/Resources.resw similarity index 100% rename from src/Calculator/Resources/el-GR/Resources.resw rename to src/Calculator.Shared/Resources/el-GR/Resources.resw diff --git a/src/Calculator/Resources/en-GB/CEngineStrings.resw b/src/Calculator.Shared/Resources/en-GB/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/en-GB/CEngineStrings.resw rename to src/Calculator.Shared/Resources/en-GB/CEngineStrings.resw diff --git a/src/Calculator/Resources/en-GB/Resources.resw b/src/Calculator.Shared/Resources/en-GB/Resources.resw similarity index 100% rename from src/Calculator/Resources/en-GB/Resources.resw rename to src/Calculator.Shared/Resources/en-GB/Resources.resw diff --git a/src/Calculator/Resources/en-US/CEngineStrings.resw b/src/Calculator.Shared/Resources/en-US/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/en-US/CEngineStrings.resw rename to src/Calculator.Shared/Resources/en-US/CEngineStrings.resw diff --git a/src/Calculator/Resources/en-US/Resources.resw b/src/Calculator.Shared/Resources/en-US/Resources.resw similarity index 100% rename from src/Calculator/Resources/en-US/Resources.resw rename to src/Calculator.Shared/Resources/en-US/Resources.resw diff --git a/src/Calculator/Resources/es-ES/CEngineStrings.resw b/src/Calculator.Shared/Resources/es-ES/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/es-ES/CEngineStrings.resw rename to src/Calculator.Shared/Resources/es-ES/CEngineStrings.resw diff --git a/src/Calculator/Resources/es-ES/Resources.resw b/src/Calculator.Shared/Resources/es-ES/Resources.resw similarity index 100% rename from src/Calculator/Resources/es-ES/Resources.resw rename to src/Calculator.Shared/Resources/es-ES/Resources.resw diff --git a/src/Calculator/Resources/es-MX/CEngineStrings.resw b/src/Calculator.Shared/Resources/es-MX/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/es-MX/CEngineStrings.resw rename to src/Calculator.Shared/Resources/es-MX/CEngineStrings.resw diff --git a/src/Calculator/Resources/es-MX/Resources.resw b/src/Calculator.Shared/Resources/es-MX/Resources.resw similarity index 100% rename from src/Calculator/Resources/es-MX/Resources.resw rename to src/Calculator.Shared/Resources/es-MX/Resources.resw diff --git a/src/Calculator/Resources/et-EE/CEngineStrings.resw b/src/Calculator.Shared/Resources/et-EE/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/et-EE/CEngineStrings.resw rename to src/Calculator.Shared/Resources/et-EE/CEngineStrings.resw diff --git a/src/Calculator/Resources/et-EE/Resources.resw b/src/Calculator.Shared/Resources/et-EE/Resources.resw similarity index 100% rename from src/Calculator/Resources/et-EE/Resources.resw rename to src/Calculator.Shared/Resources/et-EE/Resources.resw diff --git a/src/Calculator/Resources/eu-ES/CEngineStrings.resw b/src/Calculator.Shared/Resources/eu-ES/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/eu-ES/CEngineStrings.resw rename to src/Calculator.Shared/Resources/eu-ES/CEngineStrings.resw diff --git a/src/Calculator/Resources/eu-ES/Resources.resw b/src/Calculator.Shared/Resources/eu-ES/Resources.resw similarity index 100% rename from src/Calculator/Resources/eu-ES/Resources.resw rename to src/Calculator.Shared/Resources/eu-ES/Resources.resw diff --git a/src/Calculator/Resources/fa-IR/CEngineStrings.resw b/src/Calculator.Shared/Resources/fa-IR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/fa-IR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/fa-IR/CEngineStrings.resw diff --git a/src/Calculator/Resources/fa-IR/Resources.resw b/src/Calculator.Shared/Resources/fa-IR/Resources.resw similarity index 100% rename from src/Calculator/Resources/fa-IR/Resources.resw rename to src/Calculator.Shared/Resources/fa-IR/Resources.resw diff --git a/src/Calculator/Resources/fi-FI/CEngineStrings.resw b/src/Calculator.Shared/Resources/fi-FI/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/fi-FI/CEngineStrings.resw rename to src/Calculator.Shared/Resources/fi-FI/CEngineStrings.resw diff --git a/src/Calculator/Resources/fi-FI/Resources.resw b/src/Calculator.Shared/Resources/fi-FI/Resources.resw similarity index 100% rename from src/Calculator/Resources/fi-FI/Resources.resw rename to src/Calculator.Shared/Resources/fi-FI/Resources.resw diff --git a/src/Calculator/Resources/fil-PH/CEngineStrings.resw b/src/Calculator.Shared/Resources/fil-PH/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/fil-PH/CEngineStrings.resw rename to src/Calculator.Shared/Resources/fil-PH/CEngineStrings.resw diff --git a/src/Calculator/Resources/fil-PH/Resources.resw b/src/Calculator.Shared/Resources/fil-PH/Resources.resw similarity index 100% rename from src/Calculator/Resources/fil-PH/Resources.resw rename to src/Calculator.Shared/Resources/fil-PH/Resources.resw diff --git a/src/Calculator/Resources/fr-CA/CEngineStrings.resw b/src/Calculator.Shared/Resources/fr-CA/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/fr-CA/CEngineStrings.resw rename to src/Calculator.Shared/Resources/fr-CA/CEngineStrings.resw diff --git a/src/Calculator/Resources/fr-CA/Resources.resw b/src/Calculator.Shared/Resources/fr-CA/Resources.resw similarity index 100% rename from src/Calculator/Resources/fr-CA/Resources.resw rename to src/Calculator.Shared/Resources/fr-CA/Resources.resw diff --git a/src/Calculator/Resources/fr-FR/CEngineStrings.resw b/src/Calculator.Shared/Resources/fr-FR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/fr-FR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/fr-FR/CEngineStrings.resw diff --git a/src/Calculator/Resources/fr-FR/Resources.resw b/src/Calculator.Shared/Resources/fr-FR/Resources.resw similarity index 100% rename from src/Calculator/Resources/fr-FR/Resources.resw rename to src/Calculator.Shared/Resources/fr-FR/Resources.resw diff --git a/src/Calculator/Resources/gl-ES/CEngineStrings.resw b/src/Calculator.Shared/Resources/gl-ES/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/gl-ES/CEngineStrings.resw rename to src/Calculator.Shared/Resources/gl-ES/CEngineStrings.resw diff --git a/src/Calculator/Resources/gl-ES/Resources.resw b/src/Calculator.Shared/Resources/gl-ES/Resources.resw similarity index 100% rename from src/Calculator/Resources/gl-ES/Resources.resw rename to src/Calculator.Shared/Resources/gl-ES/Resources.resw diff --git a/src/Calculator/Resources/ha-Latn-NG/CEngineStrings.resw b/src/Calculator.Shared/Resources/ha-Latn-NG/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ha-Latn-NG/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ha-Latn-NG/CEngineStrings.resw diff --git a/src/Calculator/Resources/ha-Latn-NG/Resources.resw b/src/Calculator.Shared/Resources/ha-Latn-NG/Resources.resw similarity index 100% rename from src/Calculator/Resources/ha-Latn-NG/Resources.resw rename to src/Calculator.Shared/Resources/ha-Latn-NG/Resources.resw diff --git a/src/Calculator/Resources/he-IL/CEngineStrings.resw b/src/Calculator.Shared/Resources/he-IL/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/he-IL/CEngineStrings.resw rename to src/Calculator.Shared/Resources/he-IL/CEngineStrings.resw diff --git a/src/Calculator/Resources/he-IL/Resources.resw b/src/Calculator.Shared/Resources/he-IL/Resources.resw similarity index 100% rename from src/Calculator/Resources/he-IL/Resources.resw rename to src/Calculator.Shared/Resources/he-IL/Resources.resw diff --git a/src/Calculator/Resources/hi-IN/CEngineStrings.resw b/src/Calculator.Shared/Resources/hi-IN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/hi-IN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/hi-IN/CEngineStrings.resw diff --git a/src/Calculator/Resources/hi-IN/Resources.resw b/src/Calculator.Shared/Resources/hi-IN/Resources.resw similarity index 100% rename from src/Calculator/Resources/hi-IN/Resources.resw rename to src/Calculator.Shared/Resources/hi-IN/Resources.resw diff --git a/src/Calculator/Resources/hr-HR/CEngineStrings.resw b/src/Calculator.Shared/Resources/hr-HR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/hr-HR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/hr-HR/CEngineStrings.resw diff --git a/src/Calculator/Resources/hr-HR/Resources.resw b/src/Calculator.Shared/Resources/hr-HR/Resources.resw similarity index 100% rename from src/Calculator/Resources/hr-HR/Resources.resw rename to src/Calculator.Shared/Resources/hr-HR/Resources.resw diff --git a/src/Calculator/Resources/hu-HU/CEngineStrings.resw b/src/Calculator.Shared/Resources/hu-HU/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/hu-HU/CEngineStrings.resw rename to src/Calculator.Shared/Resources/hu-HU/CEngineStrings.resw diff --git a/src/Calculator/Resources/hu-HU/Resources.resw b/src/Calculator.Shared/Resources/hu-HU/Resources.resw similarity index 100% rename from src/Calculator/Resources/hu-HU/Resources.resw rename to src/Calculator.Shared/Resources/hu-HU/Resources.resw diff --git a/src/Calculator/Resources/id-ID/CEngineStrings.resw b/src/Calculator.Shared/Resources/id-ID/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/id-ID/CEngineStrings.resw rename to src/Calculator.Shared/Resources/id-ID/CEngineStrings.resw diff --git a/src/Calculator/Resources/id-ID/Resources.resw b/src/Calculator.Shared/Resources/id-ID/Resources.resw similarity index 100% rename from src/Calculator/Resources/id-ID/Resources.resw rename to src/Calculator.Shared/Resources/id-ID/Resources.resw diff --git a/src/Calculator/Resources/is-IS/CEngineStrings.resw b/src/Calculator.Shared/Resources/is-IS/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/is-IS/CEngineStrings.resw rename to src/Calculator.Shared/Resources/is-IS/CEngineStrings.resw diff --git a/src/Calculator/Resources/is-IS/Resources.resw b/src/Calculator.Shared/Resources/is-IS/Resources.resw similarity index 100% rename from src/Calculator/Resources/is-IS/Resources.resw rename to src/Calculator.Shared/Resources/is-IS/Resources.resw diff --git a/src/Calculator/Resources/it-IT/CEngineStrings.resw b/src/Calculator.Shared/Resources/it-IT/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/it-IT/CEngineStrings.resw rename to src/Calculator.Shared/Resources/it-IT/CEngineStrings.resw diff --git a/src/Calculator/Resources/it-IT/Resources.resw b/src/Calculator.Shared/Resources/it-IT/Resources.resw similarity index 100% rename from src/Calculator/Resources/it-IT/Resources.resw rename to src/Calculator.Shared/Resources/it-IT/Resources.resw diff --git a/src/Calculator/Resources/ja-JP/CEngineStrings.resw b/src/Calculator.Shared/Resources/ja-JP/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ja-JP/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ja-JP/CEngineStrings.resw diff --git a/src/Calculator/Resources/ja-JP/Resources.resw b/src/Calculator.Shared/Resources/ja-JP/Resources.resw similarity index 100% rename from src/Calculator/Resources/ja-JP/Resources.resw rename to src/Calculator.Shared/Resources/ja-JP/Resources.resw diff --git a/src/Calculator/Resources/kk-KZ/CEngineStrings.resw b/src/Calculator.Shared/Resources/kk-KZ/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/kk-KZ/CEngineStrings.resw rename to src/Calculator.Shared/Resources/kk-KZ/CEngineStrings.resw diff --git a/src/Calculator/Resources/kk-KZ/Resources.resw b/src/Calculator.Shared/Resources/kk-KZ/Resources.resw similarity index 100% rename from src/Calculator/Resources/kk-KZ/Resources.resw rename to src/Calculator.Shared/Resources/kk-KZ/Resources.resw diff --git a/src/Calculator/Resources/km-KH/CEngineStrings.resw b/src/Calculator.Shared/Resources/km-KH/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/km-KH/CEngineStrings.resw rename to src/Calculator.Shared/Resources/km-KH/CEngineStrings.resw diff --git a/src/Calculator/Resources/km-KH/Resources.resw b/src/Calculator.Shared/Resources/km-KH/Resources.resw similarity index 100% rename from src/Calculator/Resources/km-KH/Resources.resw rename to src/Calculator.Shared/Resources/km-KH/Resources.resw diff --git a/src/Calculator/Resources/kn-IN/CEngineStrings.resw b/src/Calculator.Shared/Resources/kn-IN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/kn-IN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/kn-IN/CEngineStrings.resw diff --git a/src/Calculator/Resources/kn-IN/Resources.resw b/src/Calculator.Shared/Resources/kn-IN/Resources.resw similarity index 100% rename from src/Calculator/Resources/kn-IN/Resources.resw rename to src/Calculator.Shared/Resources/kn-IN/Resources.resw diff --git a/src/Calculator/Resources/ko-KR/CEngineStrings.resw b/src/Calculator.Shared/Resources/ko-KR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ko-KR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ko-KR/CEngineStrings.resw diff --git a/src/Calculator/Resources/ko-KR/Resources.resw b/src/Calculator.Shared/Resources/ko-KR/Resources.resw similarity index 100% rename from src/Calculator/Resources/ko-KR/Resources.resw rename to src/Calculator.Shared/Resources/ko-KR/Resources.resw diff --git a/src/Calculator/Resources/lo-LA/CEngineStrings.resw b/src/Calculator.Shared/Resources/lo-LA/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/lo-LA/CEngineStrings.resw rename to src/Calculator.Shared/Resources/lo-LA/CEngineStrings.resw diff --git a/src/Calculator/Resources/lo-LA/Resources.resw b/src/Calculator.Shared/Resources/lo-LA/Resources.resw similarity index 100% rename from src/Calculator/Resources/lo-LA/Resources.resw rename to src/Calculator.Shared/Resources/lo-LA/Resources.resw diff --git a/src/Calculator/Resources/lt-LT/CEngineStrings.resw b/src/Calculator.Shared/Resources/lt-LT/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/lt-LT/CEngineStrings.resw rename to src/Calculator.Shared/Resources/lt-LT/CEngineStrings.resw diff --git a/src/Calculator/Resources/lt-LT/Resources.resw b/src/Calculator.Shared/Resources/lt-LT/Resources.resw similarity index 100% rename from src/Calculator/Resources/lt-LT/Resources.resw rename to src/Calculator.Shared/Resources/lt-LT/Resources.resw diff --git a/src/Calculator/Resources/lv-LV/CEngineStrings.resw b/src/Calculator.Shared/Resources/lv-LV/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/lv-LV/CEngineStrings.resw rename to src/Calculator.Shared/Resources/lv-LV/CEngineStrings.resw diff --git a/src/Calculator/Resources/lv-LV/Resources.resw b/src/Calculator.Shared/Resources/lv-LV/Resources.resw similarity index 100% rename from src/Calculator/Resources/lv-LV/Resources.resw rename to src/Calculator.Shared/Resources/lv-LV/Resources.resw diff --git a/src/Calculator/Resources/mk-MK/CEngineStrings.resw b/src/Calculator.Shared/Resources/mk-MK/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/mk-MK/CEngineStrings.resw rename to src/Calculator.Shared/Resources/mk-MK/CEngineStrings.resw diff --git a/src/Calculator/Resources/mk-MK/Resources.resw b/src/Calculator.Shared/Resources/mk-MK/Resources.resw similarity index 100% rename from src/Calculator/Resources/mk-MK/Resources.resw rename to src/Calculator.Shared/Resources/mk-MK/Resources.resw diff --git a/src/Calculator/Resources/ml-IN/CEngineStrings.resw b/src/Calculator.Shared/Resources/ml-IN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ml-IN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ml-IN/CEngineStrings.resw diff --git a/src/Calculator/Resources/ml-IN/Resources.resw b/src/Calculator.Shared/Resources/ml-IN/Resources.resw similarity index 100% rename from src/Calculator/Resources/ml-IN/Resources.resw rename to src/Calculator.Shared/Resources/ml-IN/Resources.resw diff --git a/src/Calculator/Resources/ms-MY/CEngineStrings.resw b/src/Calculator.Shared/Resources/ms-MY/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ms-MY/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ms-MY/CEngineStrings.resw diff --git a/src/Calculator/Resources/ms-MY/Resources.resw b/src/Calculator.Shared/Resources/ms-MY/Resources.resw similarity index 100% rename from src/Calculator/Resources/ms-MY/Resources.resw rename to src/Calculator.Shared/Resources/ms-MY/Resources.resw diff --git a/src/Calculator/Resources/nb-NO/CEngineStrings.resw b/src/Calculator.Shared/Resources/nb-NO/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/nb-NO/CEngineStrings.resw rename to src/Calculator.Shared/Resources/nb-NO/CEngineStrings.resw diff --git a/src/Calculator/Resources/nb-NO/Resources.resw b/src/Calculator.Shared/Resources/nb-NO/Resources.resw similarity index 100% rename from src/Calculator/Resources/nb-NO/Resources.resw rename to src/Calculator.Shared/Resources/nb-NO/Resources.resw diff --git a/src/Calculator/Resources/nl-NL/CEngineStrings.resw b/src/Calculator.Shared/Resources/nl-NL/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/nl-NL/CEngineStrings.resw rename to src/Calculator.Shared/Resources/nl-NL/CEngineStrings.resw diff --git a/src/Calculator/Resources/nl-NL/Resources.resw b/src/Calculator.Shared/Resources/nl-NL/Resources.resw similarity index 100% rename from src/Calculator/Resources/nl-NL/Resources.resw rename to src/Calculator.Shared/Resources/nl-NL/Resources.resw diff --git a/src/Calculator/Resources/pl-PL/CEngineStrings.resw b/src/Calculator.Shared/Resources/pl-PL/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/pl-PL/CEngineStrings.resw rename to src/Calculator.Shared/Resources/pl-PL/CEngineStrings.resw diff --git a/src/Calculator/Resources/pl-PL/Resources.resw b/src/Calculator.Shared/Resources/pl-PL/Resources.resw similarity index 100% rename from src/Calculator/Resources/pl-PL/Resources.resw rename to src/Calculator.Shared/Resources/pl-PL/Resources.resw diff --git a/src/Calculator/Resources/pt-BR/CEngineStrings.resw b/src/Calculator.Shared/Resources/pt-BR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/pt-BR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/pt-BR/CEngineStrings.resw diff --git a/src/Calculator/Resources/pt-BR/Resources.resw b/src/Calculator.Shared/Resources/pt-BR/Resources.resw similarity index 100% rename from src/Calculator/Resources/pt-BR/Resources.resw rename to src/Calculator.Shared/Resources/pt-BR/Resources.resw diff --git a/src/Calculator/Resources/pt-PT/CEngineStrings.resw b/src/Calculator.Shared/Resources/pt-PT/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/pt-PT/CEngineStrings.resw rename to src/Calculator.Shared/Resources/pt-PT/CEngineStrings.resw diff --git a/src/Calculator/Resources/pt-PT/Resources.resw b/src/Calculator.Shared/Resources/pt-PT/Resources.resw similarity index 100% rename from src/Calculator/Resources/pt-PT/Resources.resw rename to src/Calculator.Shared/Resources/pt-PT/Resources.resw diff --git a/src/Calculator/Resources/ro-RO/CEngineStrings.resw b/src/Calculator.Shared/Resources/ro-RO/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ro-RO/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ro-RO/CEngineStrings.resw diff --git a/src/Calculator/Resources/ro-RO/Resources.resw b/src/Calculator.Shared/Resources/ro-RO/Resources.resw similarity index 100% rename from src/Calculator/Resources/ro-RO/Resources.resw rename to src/Calculator.Shared/Resources/ro-RO/Resources.resw diff --git a/src/Calculator/Resources/ru-RU/CEngineStrings.resw b/src/Calculator.Shared/Resources/ru-RU/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ru-RU/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ru-RU/CEngineStrings.resw diff --git a/src/Calculator/Resources/ru-RU/Resources.resw b/src/Calculator.Shared/Resources/ru-RU/Resources.resw similarity index 100% rename from src/Calculator/Resources/ru-RU/Resources.resw rename to src/Calculator.Shared/Resources/ru-RU/Resources.resw diff --git a/src/Calculator/Resources/sk-SK/CEngineStrings.resw b/src/Calculator.Shared/Resources/sk-SK/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/sk-SK/CEngineStrings.resw rename to src/Calculator.Shared/Resources/sk-SK/CEngineStrings.resw diff --git a/src/Calculator/Resources/sk-SK/Resources.resw b/src/Calculator.Shared/Resources/sk-SK/Resources.resw similarity index 100% rename from src/Calculator/Resources/sk-SK/Resources.resw rename to src/Calculator.Shared/Resources/sk-SK/Resources.resw diff --git a/src/Calculator/Resources/sl-SI/CEngineStrings.resw b/src/Calculator.Shared/Resources/sl-SI/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/sl-SI/CEngineStrings.resw rename to src/Calculator.Shared/Resources/sl-SI/CEngineStrings.resw diff --git a/src/Calculator/Resources/sl-SI/Resources.resw b/src/Calculator.Shared/Resources/sl-SI/Resources.resw similarity index 100% rename from src/Calculator/Resources/sl-SI/Resources.resw rename to src/Calculator.Shared/Resources/sl-SI/Resources.resw diff --git a/src/Calculator/Resources/sq-AL/CEngineStrings.resw b/src/Calculator.Shared/Resources/sq-AL/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/sq-AL/CEngineStrings.resw rename to src/Calculator.Shared/Resources/sq-AL/CEngineStrings.resw diff --git a/src/Calculator/Resources/sq-AL/Resources.resw b/src/Calculator.Shared/Resources/sq-AL/Resources.resw similarity index 100% rename from src/Calculator/Resources/sq-AL/Resources.resw rename to src/Calculator.Shared/Resources/sq-AL/Resources.resw diff --git a/src/Calculator/Resources/sr-Latn-RS/CEngineStrings.resw b/src/Calculator.Shared/Resources/sr-Latn-RS/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/sr-Latn-RS/CEngineStrings.resw rename to src/Calculator.Shared/Resources/sr-Latn-RS/CEngineStrings.resw diff --git a/src/Calculator/Resources/sr-Latn-RS/Resources.resw b/src/Calculator.Shared/Resources/sr-Latn-RS/Resources.resw similarity index 100% rename from src/Calculator/Resources/sr-Latn-RS/Resources.resw rename to src/Calculator.Shared/Resources/sr-Latn-RS/Resources.resw diff --git a/src/Calculator/Resources/sv-SE/CEngineStrings.resw b/src/Calculator.Shared/Resources/sv-SE/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/sv-SE/CEngineStrings.resw rename to src/Calculator.Shared/Resources/sv-SE/CEngineStrings.resw diff --git a/src/Calculator/Resources/sv-SE/Resources.resw b/src/Calculator.Shared/Resources/sv-SE/Resources.resw similarity index 100% rename from src/Calculator/Resources/sv-SE/Resources.resw rename to src/Calculator.Shared/Resources/sv-SE/Resources.resw diff --git a/src/Calculator/Resources/sw-KE/CEngineStrings.resw b/src/Calculator.Shared/Resources/sw-KE/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/sw-KE/CEngineStrings.resw rename to src/Calculator.Shared/Resources/sw-KE/CEngineStrings.resw diff --git a/src/Calculator/Resources/sw-KE/Resources.resw b/src/Calculator.Shared/Resources/sw-KE/Resources.resw similarity index 100% rename from src/Calculator/Resources/sw-KE/Resources.resw rename to src/Calculator.Shared/Resources/sw-KE/Resources.resw diff --git a/src/Calculator/Resources/ta-IN/CEngineStrings.resw b/src/Calculator.Shared/Resources/ta-IN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/ta-IN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/ta-IN/CEngineStrings.resw diff --git a/src/Calculator/Resources/ta-IN/Resources.resw b/src/Calculator.Shared/Resources/ta-IN/Resources.resw similarity index 100% rename from src/Calculator/Resources/ta-IN/Resources.resw rename to src/Calculator.Shared/Resources/ta-IN/Resources.resw diff --git a/src/Calculator/Resources/te-IN/CEngineStrings.resw b/src/Calculator.Shared/Resources/te-IN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/te-IN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/te-IN/CEngineStrings.resw diff --git a/src/Calculator/Resources/te-IN/Resources.resw b/src/Calculator.Shared/Resources/te-IN/Resources.resw similarity index 100% rename from src/Calculator/Resources/te-IN/Resources.resw rename to src/Calculator.Shared/Resources/te-IN/Resources.resw diff --git a/src/Calculator/Resources/th-TH/CEngineStrings.resw b/src/Calculator.Shared/Resources/th-TH/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/th-TH/CEngineStrings.resw rename to src/Calculator.Shared/Resources/th-TH/CEngineStrings.resw diff --git a/src/Calculator/Resources/th-TH/Resources.resw b/src/Calculator.Shared/Resources/th-TH/Resources.resw similarity index 100% rename from src/Calculator/Resources/th-TH/Resources.resw rename to src/Calculator.Shared/Resources/th-TH/Resources.resw diff --git a/src/Calculator/Resources/tr-TR/CEngineStrings.resw b/src/Calculator.Shared/Resources/tr-TR/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/tr-TR/CEngineStrings.resw rename to src/Calculator.Shared/Resources/tr-TR/CEngineStrings.resw diff --git a/src/Calculator/Resources/tr-TR/Resources.resw b/src/Calculator.Shared/Resources/tr-TR/Resources.resw similarity index 100% rename from src/Calculator/Resources/tr-TR/Resources.resw rename to src/Calculator.Shared/Resources/tr-TR/Resources.resw diff --git a/src/Calculator/Resources/uk-UA/CEngineStrings.resw b/src/Calculator.Shared/Resources/uk-UA/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/uk-UA/CEngineStrings.resw rename to src/Calculator.Shared/Resources/uk-UA/CEngineStrings.resw diff --git a/src/Calculator/Resources/uk-UA/Resources.resw b/src/Calculator.Shared/Resources/uk-UA/Resources.resw similarity index 100% rename from src/Calculator/Resources/uk-UA/Resources.resw rename to src/Calculator.Shared/Resources/uk-UA/Resources.resw diff --git a/src/Calculator/Resources/uz-Latn-UZ/CEngineStrings.resw b/src/Calculator.Shared/Resources/uz-Latn-UZ/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/uz-Latn-UZ/CEngineStrings.resw rename to src/Calculator.Shared/Resources/uz-Latn-UZ/CEngineStrings.resw diff --git a/src/Calculator/Resources/uz-Latn-UZ/Resources.resw b/src/Calculator.Shared/Resources/uz-Latn-UZ/Resources.resw similarity index 100% rename from src/Calculator/Resources/uz-Latn-UZ/Resources.resw rename to src/Calculator.Shared/Resources/uz-Latn-UZ/Resources.resw diff --git a/src/Calculator/Resources/vi-VN/CEngineStrings.resw b/src/Calculator.Shared/Resources/vi-VN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/vi-VN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/vi-VN/CEngineStrings.resw diff --git a/src/Calculator/Resources/vi-VN/Resources.resw b/src/Calculator.Shared/Resources/vi-VN/Resources.resw similarity index 100% rename from src/Calculator/Resources/vi-VN/Resources.resw rename to src/Calculator.Shared/Resources/vi-VN/Resources.resw diff --git a/src/Calculator/Resources/zh-CN/CEngineStrings.resw b/src/Calculator.Shared/Resources/zh-CN/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/zh-CN/CEngineStrings.resw rename to src/Calculator.Shared/Resources/zh-CN/CEngineStrings.resw diff --git a/src/Calculator/Resources/zh-CN/Resources.resw b/src/Calculator.Shared/Resources/zh-CN/Resources.resw similarity index 100% rename from src/Calculator/Resources/zh-CN/Resources.resw rename to src/Calculator.Shared/Resources/zh-CN/Resources.resw diff --git a/src/Calculator/Resources/zh-TW/CEngineStrings.resw b/src/Calculator.Shared/Resources/zh-TW/CEngineStrings.resw similarity index 100% rename from src/Calculator/Resources/zh-TW/CEngineStrings.resw rename to src/Calculator.Shared/Resources/zh-TW/CEngineStrings.resw diff --git a/src/Calculator/Resources/zh-TW/Resources.resw b/src/Calculator.Shared/Resources/zh-TW/Resources.resw similarity index 100% rename from src/Calculator/Resources/zh-TW/Resources.resw rename to src/Calculator.Shared/Resources/zh-TW/Resources.resw diff --git a/src/Calculator.Shared/Styles.xaml b/src/Calculator.Shared/Styles.xaml new file mode 100644 index 00000000..98abae65 --- /dev/null +++ b/src/Calculator.Shared/Styles.xaml @@ -0,0 +1,1759 @@ + + + + + + + + + + + 0,0,0,0 + + + + 0 + + + + #FF000000 + + + + #FF2B2B2B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500 + 320 + + ms-appx:///Assets/CalcMDL2.ttf#Calculator MDL2 Assets + + 256 + 0,1,0,0 + 15 + SemiBold + + 12 + 15 + 24 + + + 40 + 40 + + 34 + 24 + + 20 + + 15 + + 72 + 46 + 28 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Calculator.Shared/ViewModels/ApplicationViewModel.cs b/src/Calculator.Shared/ViewModels/ApplicationViewModel.cs new file mode 100644 index 00000000..6694811b --- /dev/null +++ b/src/Calculator.Shared/ViewModels/ApplicationViewModel.cs @@ -0,0 +1,231 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp; +using CalculatorApp.Common; +using CalculatorApp.ViewModel; +using CalculationManager; +using Windows.System; +using Windows.Storage; +using Windows.Foundation.Collections; +using Windows.Globalization; +using Windows.UI.ViewManagement; +using Windows.UI.Core; +using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using System.ComponentModel; +using System.Windows.Input; +using System; +using System.Diagnostics; +using System.Collections.ObjectModel; + +namespace CalculatorApp.ViewModel +{ + public class ApplicationViewModel : INotifyPropertyChanged + { + string CategoriesPropertyName = "Categories"; + string ClearMemoryVisibilityPropertyName = "ClearMemoryVisibility"; + + + public event PropertyChangedEventHandler PropertyChanged; + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); + private StandardCalculatorViewModel m_CalculatorViewModel; + public StandardCalculatorViewModel CalculatorViewModel { get => m_CalculatorViewModel; set { m_CalculatorViewModel = value; RaisePropertyChanged("CalculatorViewModel"); } } + + // UNO TODO + //private DateCalculatorViewModel m_DateCalcViewModel; + //public DateCalculatorViewModel DateCalcViewModel { get => m_DateCalcViewModel; set { m_DateCalcViewModel = value; RaisePropertyChanged("DateCalcViewModel"); } } + + + // UNO TODO + //private UnitConverterViewModel m_ConverterViewModel; + //public UnitConverterViewModel ConverterViewModel { get => m_ConverterViewModel; set { m_ConverterViewModel = value; RaisePropertyChanged("ConverterViewModel"); } } + + + private CalculatorApp.Common.ViewMode m_PreviousMode; + public CalculatorApp.Common.ViewMode PreviousMode { get => m_PreviousMode; set { m_PreviousMode = value; RaisePropertyChanged("PreviousMode"); } } + + + private const string CategoryNameName = "CategoryName"; + private string m_CategoryName; + public string CategoryName { get => m_CategoryName; set { m_CategoryName = value; RaisePropertyChanged("CategoryName"); } } + + + public ICommand CopyCommand { get; } + + + public ICommand PasteCommand { get; } + + + + + ViewMode m_mode = ViewMode.None; + ObservableCollection m_categories; + + public ApplicationViewModel() + { + CopyCommand = new DelegateCommand(OnCopyCommand); + PasteCommand = new DelegateCommand(OnPasteCommand); + + SetMenuCategories(); + } + + public ViewMode Mode + { + get => m_mode; + set + { + if (m_mode != value) + { + PreviousMode = m_mode; + m_mode = value; + OnModeChanged(); + RaisePropertyChanged(); + } + } + } + + public ObservableCollection Categories + { + get => m_categories; + set + { + if (m_categories != value) + { + m_categories = value; + RaisePropertyChanged(CategoriesPropertyName); + } + } + } + + public void Initialize(ViewMode mode) + { + if (!NavCategory.IsValidViewMode(mode)) + { + mode = ViewMode.Standard; + } + + try + { + Mode = mode; + } + catch (Exception e) + { + // TraceLogger.GetInstance().LogPlatformException(__FUNCTIONW__, e); + if (!TryRecoverFromNavigationModeFailure()) + { + // Could not navigate to standard mode either. + // Throw the original exception so we have a good stack to debug. + throw; + } + } + } + + bool TryRecoverFromNavigationModeFailure() + { + // Here we are simply trying to recover from being unable to navigate to a mode. + // Try falling back to standard mode and if there are *any* exceptions, we should + // fail because something is seriously wrong. + try + { + Mode = ViewMode.Standard; + return true; + } + catch + { + return false; + } + } + + void OnModeChanged() + { + Debug.Assert(NavCategory.IsValidViewMode(m_mode)); + // TraceLogger.GetInstance().LogModeChangeBegin(m_PreviousMode, m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())); + if (NavCategory.IsCalculatorViewMode(m_mode)) + { + // TraceLogger.GetInstance().LogCalculatorModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())); + if (m_CalculatorViewModel == null) + { + m_CalculatorViewModel = new StandardCalculatorViewModel(); + } + m_CalculatorViewModel.SetCalculatorType(m_mode); + } + else if (NavCategory.IsDateCalculatorViewMode(m_mode)) + { + // TraceLogger.GetInstance().LogDateCalculatorModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())); + // UNO TODO + //if (m_DateCalcViewModel == null) + //{ + // m_DateCalcViewModel = new DateCalculatorViewModel(); + //} + } + else if (NavCategory.IsConverterViewMode(m_mode)) + { + // UNO TODO + //// TraceLogger.GetInstance().LogConverterModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())); + //if (!m_ConverterViewModel) + //{ + // var dataLoader = new UnitConverterDataLoader(new GeographicRegion()); + // var currencyDataLoader = new CurrencyDataLoader(new CurrencyHttpClient()); + // m_ConverterViewModel = new UnitConverterViewModel(new UnitConversionManager.UnitConverter(dataLoader, currencyDataLoader)); + //} + + //m_ConverterViewModel.Mode = m_mode; + } + + var resProvider = AppResourceProvider.GetInstance(); + CategoryName = resProvider.GetResourceString(NavCategory.GetNameResourceKey(m_mode)); + + // This is the only place where a ViewMode enum should be cast to an int. + // + // Save the changed mode, so that the new window launches in this mode. + // Don't save until after we have adjusted to the new mode, so we don't save a mode that fails to load. + ApplicationData.Current.LocalSettings.Values[nameof(Mode)] = NavCategory.Serialize(m_mode); + + // TraceLogger.GetInstance().LogModeChangeEnd(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())); + RaisePropertyChanged(ClearMemoryVisibilityPropertyName); + } + + void OnCopyCommand(object parameter) + { + // UNO TODO + //if (NavCategory.IsConverterViewMode(m_mode)) + //{ + // ConverterViewModel.OnCopyCommand(parameter); + //} + //else if (NavCategory.IsDateCalculatorViewMode(m_mode)) + //{ + // DateCalcViewModel.OnCopyCommand(parameter); + //} + //else + { + CalculatorViewModel.OnCopyCommand(parameter); + } + } + + void OnPasteCommand(object parameter) + { + // UNO TODO + //if (NavCategory.IsConverterViewMode(m_mode)) + //{ + // ConverterViewModel.OnPasteCommand(parameter); + //} + //else + if (NavCategory.IsCalculatorViewMode(m_mode)) + { + CalculatorViewModel.OnPasteCommand(parameter); + } + } + + void SetMenuCategories() + { + // Use the Categories property instead of the backing variable + // because we want to take advantage of binding updates and + // property setter logic. + Categories = NavCategoryGroup.CreateMenuOptions(); + } + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/ViewModels/DateCalculatorViewModel.cs b/src/Calculator.Shared/ViewModels/DateCalculatorViewModel.cs new file mode 100644 index 00000000..c7778222 --- /dev/null +++ b/src/Calculator.Shared/ViewModels/DateCalculatorViewModel.cs @@ -0,0 +1,531 @@ +//using System; +//using System.Collections.Generic; +//using System.ComponentModel; +//using System.Text; +//using Windows.UI.Xaml.Data; +//using Windows.Globalization; +//using CalculatorApp.Common; +//using Windows.Globalization.DateTimeFormatting; +//using CalculatorApp.Common.DateCalculation; +//using Windows.Foundation; +//using Platform.Collections; +//using System.Numerics; + +//namespace WindowsCalculator.Shared.ViewModels +//{ +// /* MAX? +// { +// StringReference StrDateDiffResult(L"StrDateDiffResult"); +// StringReference StrDateDiffResultAutomationName(L"StrDateDiffResultAutomationName"); +// StringReference StrDateDiffResultInDays(L"StrDateDiffResultInDays"); +// StringReference StrDateResult(L"StrDateResult"); +// StringReference StrDateResultAutomationName(L"StrDateResultAutomationName"); +// StringReference IsDiffInDays(L"IsDiffInDays"); +// } +// */ + +// [Bindable] +// public sealed class DateCalculatorViewModel : INotifyPropertyChanged +// { +// // Private members +// private DateCalculationEngine m_dateCalcEngine; +// private DateUnit m_daysOutputFormat; +// private DateUnit m_allDateUnitsOutputFormat; +// private DateTimeFormatter m_dateTimeFormatter; +// private string m_listSeparator; + +// private bool m_isOutOfBound; +// private Vector m_offsetValues; +// private DateTime m_fromDate; +// private DateTime m_toDate; +// private DateTime m_startDate; +// private DateTime m_dateResult; +// private DateDifference m_dateDiffResult; +// private DateDifference m_dateDiffResultInDays; + +// public DateCalculatorViewModel() +// { +// m_IsDateDiffMode = true; +// m_IsAddMode = true; +// m_isOutOfBound = false; +// m_DaysOffset = 0; +// m_MonthsOffset = 0; +// m_YearsOffset = 0; +// m_StrDateDiffResult = ""; +// m_StrDateDiffResultAutomationName = ""; +// m_StrDateDiffResultInDays = ""; +// m_StrDateResult = ""; +// m_StrDateResultAutomationName = ""; +// m_fromDate = 0; +// m_toDate = 0; +// m_startDate = 0; +// m_dateResult = 0; + +// var localizationSettings = LocalizationSettings.GetInstance(); + +// // Initialize Date Output format instances +// InitializeDateOutputFormats(localizationSettings.GetCalendarIdentifier()); + +// // Initialize Date Calc engine +// m_dateCalcEngine = make_shared(localizationSettings.GetCalendarIdentifier()); + +// // Initialize dates of DatePicker controls to today's date +// var calendar = new Calendar(); +// var today = calendar.GetDateTime(); + +// // FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC) +// m_fromDate = today; +// m_toDate = today; +// FromDate = ClipTime(today); +// ToDate = ClipTime(today); + +// // StartDate should not be clipped +// StartDate = today; +// m_dateResult = today; + +// // Initialize the list separator delimiter appended with a space at the end, e.g. ", " +// // This will be used for date difference formatting: Y years, M months, W weeks, D days +// m_listSeparator = new String((localizationSettings.GetListSeparator() + " ").ToString()); + +// // Initialize the output results +// UpdateDisplayResult(); + +// m_offsetValues = new Vector (); + +// for (int i = 0; i <= c_maxOffsetValue; i++) +// { +// // MAX? +// string numberStr = i.ToString(); +// localizationSettings.LocalizeDisplayValue(numberStr); +// m_offsetValues.Append(numberStr.ToString()); +// } + +// /* In the ClipTime function, we used to change timezone to UTC before clipping the time. +// The comment from the previous delopers said this was done to eliminate the effects of +// Daylight Savings Time. We can't think of a good reason why this change in timezone is +// necessary and did find bugs related to the change, therefore, we have removed the +// change. Just in case, we will see if the clipped time is ever a different day from the +// original day, which would hopefully indicate the change in timezone was actually +// necessary. We will collect telemetry if we find this case. If we don't see any +// telemetry events after the application has been used for some time, we will feel safe +// and can remove this function. */ +// DayOfWeek trueDayOfWeek = calendar->DayOfWeek; + +// DateTime clippedTime = ClipTime(today); +// calendar.SetDateTime(clippedTime); + +// if (calendar->DayOfWeek != trueDayOfWeek) +// { +// // MAX? +// calendar.SetDateTime(today); +// TraceLogger.GetInstance().LogDateClippedTimeDifferenceFound( +// from_cx(calendar), +// DateTime{ TimeSpan{ clippedTime.UniversalTime } }); +// } +// } + +// static void CheckClipTimeSameDay(Calendar reference) +// { + +// } + +// private bool IsOutOfBound +// { +// get { return m_isOutOfBound; } +// set +// { +// m_isOutOfBound = value; +// UpdateDisplayResult(); +// } +// } + +// private DateDifference DateDiffResult +// { +// get { return m_dateDiffResult; } +// set { +// m_dateDiffResult = value; +// UpdateDisplayResult(); +// } +// } + +// private DateDifference DateDiffResultInDays +// { +// get { return m_dateDiffResultInDays; } +// set +// { +// m_dateDiffResultInDays = value; +// UpdateDisplayResult(); +// } +// } + +// private DateTime DateResult +// { +// get { return m_dateResult; } +// set { +// m_dateResult = value; +// UpdateDisplayResult(); +// } +// } + +// // PUBLIC + +// // Input Properties +// public string IsDateDiffMode { get; set; } +// public string IsAddMode { get; set; } +// public string IsDiffInDays { get; set; } // If diff is only in days or the dates are the same, +// // then show only one result and avoid redundancy + +// public string DaysOffset { get; set; } +// public string MonthsOffset { get; set; } +// public string YearsOffset { get; set; } + +// // Read only property for offset values +// public IVector OffsetValues +// { +// get { return m_offsetValues; } +// } + +// // From date for Date Diff +// public DateTime FromDate +// { +// DateTime get() { return m_fromDate; } +// set +// { +// if (m_fromDate.UniversalTime != value.UniversalTime) +// { +// m_fromDate = value; +// RaisePropertyChanged("FromDate"); +// } +// } +// } + +// // To date for Date Diff +// public DateTime ToDate +// { +// get { return m_toDate; } +// set +// { +// if (m_toDate.UniversalTime != value.UniversalTime) +// { +// m_toDate = value; +// RaisePropertyChanged("ToDate"); +// } +// } +// } + +// // Start date for Add/Subtract date +// public DateTime StartDate +// { +// get { return m_startDate; } +// set +// { +// if (m_startDate.UniversalTime != value.UniversalTime) +// { +// m_startDate = value; +// RaisePropertyChanged("StartDate"); +// } +// } +// } + +// // Output Properties +// public string StrDateDiffResult { get; set; } + +// public string StrDateDiffResultAutomationName { get; set; } + +// public string StrDateDiffResultInDays { get; set; } + +// public string StrDateResult { get; set; } + +// public string StrDateResultAutomationName { get; set; } + +// public void OnCopyCommand(Object parameter) +// { + +// } + +// // PRIVATE +// private void OnPropertyChanged(string prop) +// { +// if (prop == DateCalculatorViewModelProperties.StrDateDiffResult) +// { +// UpdateStrDateDiffResultAutomationName(); +// } +// else if (prop == DateCalculatorViewModelProperties.StrDateResult) +// { +// UpdateStrDateResultAutomationName(); +// } +// else if (prop != DateCalculatorViewModelProperties.StrDateDiffResultAutomationName +// && prop != DateCalculatorViewModelProperties.StrDateDiffResultInDays +// && prop != DateCalculatorViewModelProperties.StrDateResultAutomationName +// && prop != DateCalculatorViewModelProperties.IsDiffInDays) +// { +// OnInputsChanged(); +// } +// } + +// private void OnInputsChanged() +// { +// DateDifference dateDiff; + +// if (m_IsDateDiffMode) +// { +// DateTime clippedFromDate = ClipTime(FromDate); +// DateTime clippedToDate = ClipTime(ToDate); + +// // Calculate difference between two dates +// m_dateCalcEngine->GetDateDifference(clippedFromDate, clippedToDate, m_allDateUnitsOutputFormat, &dateDiff); +// DateDiffResult = dateDiff; + +// m_dateCalcEngine->GetDateDifference(clippedFromDate, clippedToDate, m_daysOutputFormat, &dateDiff); +// DateDiffResultInDays = dateDiff; +// } +// else +// { +// dateDiff.day = DaysOffset; +// dateDiff.month = MonthsOffset; +// dateDiff.year = YearsOffset; + +// DateTime dateTimeResult; + +// if (m_IsAddMode) +// { +// // Add number of Days, Months and Years to a Date +// IsOutOfBound = !m_dateCalcEngine->AddDuration(StartDate, dateDiff, &dateTimeResult); +// } +// else +// { +// // Subtract number of Days, Months and Years from a Date +// IsOutOfBound = !m_dateCalcEngine->SubtractDuration(StartDate, dateDiff, &dateTimeResult); +// } + +// if (!m_isOutOfBound) +// { +// DateResult = dateTimeResult; +// } +// } +// } + +// private void UpdateDisplayResult() +// { +// if (m_IsDateDiffMode) +// { +// // Are to and from dates the same +// if (m_dateDiffResultInDays.day == 0) +// { +// IsDiffInDays = true; +// StrDateDiffResultInDays = ""; +// StrDateDiffResult = AppResourceProvider.GetInstance().GetResourceString("Date_SameDates"); +// } +// else if ((m_dateDiffResult.year == 0) && +// (m_dateDiffResult.month == 0) && +// (m_dateDiffResult.week == 0)) +// { +// IsDiffInDays = true; +// StrDateDiffResultInDays = ""; + +// // Display result in number of days +// StrDateDiffResult = GetDateDiffStringInDays(); +// } +// else +// { +// IsDiffInDays = false; + +// // Display result in days, weeks, months and years +// StrDateDiffResult = GetDateDiffString(); + +// // Display result in number of days +// StrDateDiffResultInDays = GetDateDiffStringInDays(); +// } +// } +// else +// { +// if (m_isOutOfBound) +// { +// // Display Date out of bound message +// StrDateResult = AppResourceProvider.GetInstance().GetResourceString("Date_OutOfBoundMessage"); +// } +// else +// { +// // Display the resulting date in long format +// StrDateResult = m_dateTimeFormatter.Format(DateResult); +// } +// } +// } + +// private void UpdateStrDateDiffResultAutomationName() +// { +// String automationFormat = AppResourceProvider.GetInstance().GetResourceString("Date_DifferenceResultAutomationName"); +// String localizedAutomationName = LocalizationStringUtil.GetLocalizedString(automationFormat->Data(), StrDateDiffResult.Data()); + +// StrDateDiffResultAutomationName = new String(localizedAutomationName.ToString()); +// } + +// private void UpdateStrDateResultAutomationName() +// { +// String automationFormat = AppResourceProvider.GetInstance().GetResourceString("Date_ResultingDateAutomationName"); +// String localizedAutomationName = LocalizationStringUtil.GetLocalizedString(automationFormat.Data(), StrDateResult.Data()); + +// StrDateResultAutomationName = new String(localizedAutomationName.ToString()); +// } + +// private void InitializeDateOutputFormats(string calendarIdentifer) +// { +// // Format for Add/Subtract days +// m_dateTimeFormatter = LocalizationService.GetRegionalSettingsAwareDateTimeFormatter( +// "longdate", +// calendarIdentifier, +// ClockIdentifiers.TwentyFourHour); // Clock Identifier is not used + +// // Format for Date Difference +// m_allDateUnitsOutputFormat = DateUnit.Year | DateUnit.Month | DateUnit.Week | DateUnit.Day; +// m_daysOutputFormat = DateUnit.Day; +// } + +// private string GetDateDiffString() +// { +// String result = ""; +// bool addDelimiter = false; +// AppResourceProvider resourceLoader = AppResourceProvider.GetInstance(); + +// var yearCount = m_dateDiffResult.year; + +// if (yearCount > 0) +// { +// result = String.Concat(GetLocalizedNumberString(yearCount), " "); + +// if (yearCount > 1) +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Years")); +// } +// else +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Year")); +// } + +// // set the flags to add a delimiter whenever the next unit is added +// addDelimiter = true; +// } + +// var monthCount = m_dateDiffResult.month; + +// if (monthCount > 0) +// { +// if (addDelimiter) +// { +// result = String.Concat(result, m_listSeparator); +// } +// else +// { +// addDelimiter = true; +// } + +// result = String.Concat(result, String.Concat(GetLocalizedNumberString(monthCount), " ")); + +// if (monthCount > 1) +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Months")); +// } +// else +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Month")); +// } +// } + +// var weekCount = m_dateDiffResult.week; + +// if (weekCount > 0) +// { +// if (addDelimiter) +// { +// result = String.Concat(result, m_listSeparator); +// } +// else +// { +// addDelimiter = true; +// } + +// result = String.Concat(result, String.Concat(GetLocalizedNumberString(weekCount), " ")); + +// if (weekCount > 1) +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Weeks")); +// } +// else +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Week")); +// } +// } + +// var dayCount = m_dateDiffResult.day; + +// if (dayCount > 0) +// { +// if (addDelimiter) +// { +// result = String.Concat(result, m_listSeparator); +// } +// else +// { +// addDelimiter = true; +// } + +// result = String.Concat(result, String.Concat(GetLocalizedNumberString(dayCount), " ")); + +// if (dayCount > 1) +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Days")); +// } +// else +// { +// result = String.Concat(result, resourceLoader.GetResourceString("Date_Day")); +// } +// } + +// return result; +// } + +// private string GetDateDiffStringInDays() +// { +// String strDateUnit; + +// // Display the result as '1 day' or 'N days' +// if (m_dateDiffResultInDays.day > 1) +// { +// strDateUnit = AppResourceProvider.GetInstance().GetResourceString("Date_Days"); +// } +// else +// { +// strDateUnit = AppResourceProvider.GetInstance().GetResourceString("Date_Day"); +// } + +// return String.Concat(GetLocalizedNumberString(m_dateDiffResultInDays.day), String.Concat(" ", strDateUnit)); +// } + +// private string GetLocalizedNumberString(int value) +// { +// string numberStr = value.ToString(); +// LocalizationSettings.GetInstance().LocalizeDisplayValue(numberStr); + +// return numberStr.ToString(); +// } + +// private static DateTime ClipTime(DateTime dateTime) +// { +// var calendar = new Calendar(); +// calendar.SetDateTime(dateTime); +// calendar.Period = 1; +// calendar.Hour = 12; +// calendar.Minute = 0; +// calendar.Second = 0; +// calendar.Nanosecond = 0; + +// return calendar.GetDateTime(); +// } + +// // MAX? +// private static void CheckClipTimeSameDay(Calendar reference) +// { + +// } +// } +//} \ No newline at end of file diff --git a/src/Calculator.Shared/ViewModels/HistoryItemViewModel.cs b/src/Calculator.Shared/ViewModels/HistoryItemViewModel.cs new file mode 100644 index 00000000..78f4fe97 --- /dev/null +++ b/src/Calculator.Shared/ViewModels/HistoryItemViewModel.cs @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculationManager; +using CalculatorApp.Common; +using System; +using System.Text; +using Windows.UI.Xaml.Data; + +namespace CalculatorApp +{ + namespace ViewModel + { + [Windows.UI.Xaml.Data.Bindable] + public sealed class HistoryItemViewModel : ICustomPropertyProvider + { + public CalculatorList<(string, int)> GetTokens() + { + return m_spTokens; + } + + public CalculatorList GetCommands() + { + return m_spCommands; + } + + public string Expression => m_expression; + + public string AccExpression => m_accExpression; + + public string Result => m_result; + + public string AccResult => m_accResult; + + public ICustomProperty GetCustomProperty(string name) { return null; } + + public ICustomProperty GetIndexedProperty(string name, Type type) { return null; } + + public Type Type => this.GetType(); + + public string GetStringRepresentation() { return m_accExpression + " " + m_accResult; } + + private string m_expression; + private string m_accExpression; + private string m_accResult; + private string m_result; + private CalculatorList<(string, int)> m_spTokens; + private CalculatorList m_spCommands; + + + public HistoryItemViewModel( + String expression, + String result, + CalculatorList<(string, int)> spTokens, + CalculatorList spCommands) + { + m_expression = expression; + m_result = result; + m_spTokens = spTokens; + m_spCommands = spCommands; + // updating accessibility names for expression and result + m_accExpression = GetAccessibleExpressionFromTokens(spTokens, m_expression); + m_accResult = LocalizationService.GetNarratorReadableString(m_result); + } + + string GetAccessibleExpressionFromTokens( + CalculatorList<(string, int)> spTokens, + String fallbackExpression) + { + // updating accessibility names for expression and result + StringBuilder accExpression = new StringBuilder(); + + int nTokens; + var hr = spTokens.GetSize(out nTokens); + if (hr) + { + (string, int) tokenItem; + for (int i = 0; i < nTokens; i++) + { + hr = spTokens.GetAt(i, out tokenItem); + if (!hr) + { + break; + } + + string token = tokenItem.Item1; + accExpression.Append(LocalizationService.GetNarratorReadableToken(token)); + } + } + + if (hr) + { + string expressionSuffix = ""; + hr = spTokens.GetExpressionSuffix(out expressionSuffix); + if (hr) + { + accExpression.Append(expressionSuffix); + } + } + + if (!hr) + { + return LocalizationService.GetNarratorReadableString(fallbackExpression); + } + else + { + return accExpression.ToString(); + } + } + }; + } +} diff --git a/src/Calculator.Shared/ViewModels/HistoryViewModel.cs b/src/Calculator.Shared/ViewModels/HistoryViewModel.cs new file mode 100644 index 00000000..66e32701 --- /dev/null +++ b/src/Calculator.Shared/ViewModels/HistoryViewModel.cs @@ -0,0 +1,419 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +namespace CalculatorApp +{ + using CalculatorApp.Common; + using CalculatorApp.Common.Automation; + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Windows.Input; + using Windows.Storage; + using CM = CalculationManager; + + namespace ViewModel + { + public + delegate void HideHistoryClickedHandler(); + public + delegate void HistoryItemClickedHandler(CalculatorApp.ViewModel.HistoryItemViewModel e); + + [Windows.UI.Xaml.Data.Bindable] + public sealed class HistoryViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); + private int m_ItemSize; + public int ItemSize { get => m_ItemSize; set { m_ItemSize = value; RaisePropertyChanged("ItemSize"); } } + + + private ObservableCollection m_Items; + public ObservableCollection Items { get => m_Items; set { m_Items = value; RaisePropertyChanged("Items"); } } + + + private bool m_AreHistoryShortcutsEnabled; + public bool AreHistoryShortcutsEnabled { get => m_AreHistoryShortcutsEnabled; set { m_AreHistoryShortcutsEnabled = value; RaisePropertyChanged("AreHistoryShortcutsEnabled"); } } + + + private CalculatorApp.Common.Automation.NarratorAnnouncement m_HistoryAnnouncement; + public CalculatorApp.Common.Automation.NarratorAnnouncement HistoryAnnouncement { get => m_HistoryAnnouncement; set { m_HistoryAnnouncement = value; RaisePropertyChanged("HistoryAnnouncement"); } } + + + public ICommand HideCommand { get; } + + public ICommand ClearCommand { get; } + + // events that are created + public event HideHistoryClickedHandler HideHistoryClicked; + public event HistoryItemClickedHandler HistoryItemClicked; + + CalculationManager.CalculatorManager m_calculatorManager; + CalculatorDisplay m_calculatorDisplay; + CalculationManager.CALCULATOR_MODE m_currentMode; + string m_localizedHistoryCleared; + + + static string HistoryVectorLengthKey = "HistoryVectorLength"; + + const string HistoryCleared = "HistoryList_Cleared"; + + public HistoryViewModel(CalculationManager.CalculatorManager calculatorManager) + { + HideCommand = new DelegateCommand(OnHideCommand); + ClearCommand = new DelegateCommand(OnClearCommand); + + m_calculatorManager = calculatorManager; + m_localizedHistoryCleared = null; + + AreHistoryShortcutsEnabled = true; + + Items = new ObservableCollection(); + ItemSize = 0; + } + + void RestoreCompleteHistory() + { + RestoreHistory(CalculationManager.CALCULATOR_MODE.CM_STD); + RestoreHistory(CalculationManager.CALCULATOR_MODE.CM_SCI); + } + + // this will reload Items with the history list based on current mode + public void ReloadHistory(ViewMode currentMode) + { + if (currentMode == ViewMode.Standard) + { + m_currentMode = CalculationManager.CALCULATOR_MODE.CM_STD; + } + else if (currentMode == ViewMode.Scientific) + { + m_currentMode = CalculationManager.CALCULATOR_MODE.CM_SCI; + } + else + { + return; + } + + var historyListModel = m_calculatorManager.GetHistoryItems(m_currentMode); + var historyListVM = new ObservableCollection(); + var localizer = LocalizationSettings.GetInstance(); + if (historyListModel.Count > 0) + { + foreach(var it in historyListModel.AsEnumerable().Reverse()) + { + string expression = it.historyItemVector.expression; + string result = it.historyItemVector.result; + localizer.LocalizeDisplayValue(ref expression); + localizer.LocalizeDisplayValue(ref result); + + var item = new HistoryItemViewModel( + expression, + result, + it.historyItemVector.spTokens, + it.historyItemVector.spCommands); + historyListVM.Add(item); + } + } + + Items = historyListVM; + UpdateItemSize(); + } + + public void OnHistoryItemAdded(int addedItemIndex) + { + var newItem = m_calculatorManager.GetHistoryItem(addedItemIndex); + var localizer = LocalizationSettings.GetInstance(); + string expression = newItem.historyItemVector.expression; + string result = newItem.historyItemVector.result; + localizer.LocalizeDisplayValue(ref expression); + localizer.LocalizeDisplayValue(ref result); + var item = new HistoryItemViewModel( + expression, + result, + newItem.historyItemVector.spTokens, + newItem.historyItemVector.spCommands); + + // check if we have not hit the max items + if (Items.Count >= m_calculatorManager.MaxHistorySize()) + { + // this means the item already exists + Items.RemoveAt(Items.Count - 1); + } + + Debug.Assert(addedItemIndex <= m_calculatorManager.MaxHistorySize() && addedItemIndex >= 0); + Items.Insert(0, item); + UpdateItemSize(); + SaveHistory(); + } + + public void SetCalculatorDisplay(CalculatorDisplay calculatorDisplay) + { + calculatorDisplay.SetHistoryCallback(new WeakReference(this)); + } + + void ShowItem(HistoryItemViewModel e) + { + HistoryItemClicked(e); + } + + void DeleteItem(HistoryItemViewModel e) + { + int itemIndex= Items.IndexOf(e); + if (itemIndex != -1) + { + if (m_calculatorManager.RemoveHistoryItem(itemIndex)) + { + // Keys for the history container are index based. + // SaveHistory() re-inserts the items anyway, so it's faster to just clear out the container. + CalculationManager.CALCULATOR_MODE currentMode = m_currentMode; + ApplicationDataContainer historyContainer = GetHistoryContainer(currentMode); + historyContainer.Values.Clear(); + + Items.RemoveAt(itemIndex); + UpdateItemSize(); + SaveHistory(); + } + } + } + + void OnHideCommand(object e) + { + // added at VM layer so that the views do not have to individually raise events + HideHistoryClicked(); + } + + void OnClearCommand(object e) + { + // TraceLogger.GetInstance().LogClearHistory(); + if (AreHistoryShortcutsEnabled == true) + { + m_calculatorManager.ClearHistory(); + + if (Items.Count > 0) + { + CalculationManager.CALCULATOR_MODE currentMode = m_currentMode; + ClearHistoryContainer(currentMode); + Items.Clear(); + UpdateItemSize(); + } + + MakeHistoryClearedNarratorAnnouncement(HistoryCleared, m_localizedHistoryCleared); + } + } + + // this method restores history vector per mode + void RestoreHistory(CalculationManager.CALCULATOR_MODE cMode) + { + ApplicationDataContainer historyContainer = GetHistoryContainer(cMode); + List historyVector = new List(); + var historyVectorLength = (int)(historyContainer.Values[HistoryVectorLengthKey]); + bool failure = false; + + if (historyVectorLength > 0) + { + for (int i = 0; i < historyVectorLength; ++i) + { + try + { + // deserialize each item + var item = DeserializeHistoryItem(i.ToString(), historyContainer); + historyVector.Add(item); + } + catch (Exception e) + { + failure = true; + break; + } + } + + if (!failure) + { + // if task has been cancelled set history to 0 + m_calculatorManager.SetHistory(cMode, historyVector); + + // update length once again for consistency between stored number of items and length + UpdateHistoryVectorLength((int)(historyVector.Count), cMode); + } + else + { + // in case of failure do not show any item + UpdateHistoryVectorLength(0, cMode); + } + } + } + + string GetHistoryContainerKey(CalculationManager.CALCULATOR_MODE cMode) + { + int modeValue = (int)(cMode); + return String.Concat(modeValue.ToString(), "_History"); + } + + ApplicationDataContainer GetHistoryContainer(CalculationManager.CALCULATOR_MODE cMode) + { + ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; + ApplicationDataContainer historyContainer; + + // naming container based on mode + string historyContainerKey = GetHistoryContainerKey(cMode); + + if (localSettings.Containers.ContainsKey(historyContainerKey)) + { + historyContainer = localSettings.Containers[historyContainerKey]; + } + else + { + // create container for adding data + historyContainer = localSettings.CreateContainer(historyContainerKey, ApplicationDataCreateDisposition.Always); + int initialHistoryVectorLength = 0; + historyContainer.Values.Add(HistoryVectorLengthKey, initialHistoryVectorLength); + } + + return historyContainer; + } + + void ClearHistoryContainer(CalculationManager.CALCULATOR_MODE cMode) + { + ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; + localSettings.DeleteContainer(GetHistoryContainerKey(cMode)); + } + + // this method will be used to update the history item length + void UpdateHistoryVectorLength(int newValue, CalculationManager.CALCULATOR_MODE cMode) + { + ApplicationDataContainer historyContainer = GetHistoryContainer(cMode); + historyContainer.Values.Remove(HistoryVectorLengthKey); + historyContainer.Values.Add(HistoryVectorLengthKey, newValue); + } + + public void ClearHistory() + { + ClearHistoryContainer(CalculationManager.CALCULATOR_MODE.CM_STD); + ClearHistoryContainer(CalculationManager.CALCULATOR_MODE.CM_SCI); + } + + void SaveHistory() + { + ApplicationDataContainer historyContainer = GetHistoryContainer(m_currentMode); + var currentHistoryVector = m_calculatorManager.GetHistoryItems(m_currentMode); + bool failure = false; + int index = 0; + string serializedHistoryItem; + + foreach(var it in currentHistoryVector) + { + try + { + serializedHistoryItem = SerializeHistoryItem(it); + historyContainer.Values.Add(index.ToString(), serializedHistoryItem); + } + catch (Exception e) + { + failure = true; + break; + } + + ++index; + } + + if (!failure) + { + // insertion is successful + UpdateHistoryVectorLength(currentHistoryVector.Count, m_currentMode); + } + else + { + UpdateHistoryVectorLength(0, m_currentMode); + } + } + + // this serializes a history item into a base64 encoded string + string SerializeHistoryItem(CalculationManager.HISTORYITEM item) + { + //DataWriter writer = new DataWriter(); + // var expr = item.historyItemVector.expression; + // var result = item.historyItemVector.result; + // var platformExpr = expr; + // writer.WriteUInt32(writer.MeasureString(platformExpr)); + //writer.WriteString(platformExpr); + //var platformResult = result; + // writer.WriteUInt32(writer.MeasureString(platformResult)); + //writer.WriteString(platformResult); + + //Utils.SerializeCommandsAndTokens(item.historyItemVector.spTokens, item.historyItemVector.spCommands, writer); + + //IBuffer buffer = writer.DetachBuffer(); + //if (buffer == null) + //{ + // throw new Platform.Exception(E_POINTER, "History Item is NULL"); + //} + + //return CryptographicBuffer.EncodeToBase64String(buffer); + return ""; + } + + CalculationManager.HISTORYITEM + DeserializeHistoryItem(string historyItemKey, ApplicationDataContainer historyContainer) + { + //CalculationManager.HISTORYITEM historyItem; + //if (historyContainer.Values.ContainsKey(historyItemKey)) + //{ + // object historyItemValues = historyContainer.Values[historyItemKey]; + + // if (historyItemValues == null) + // { + // throw new Exception("History Item is NULL"); + // } + + // String historyData = (string)(historyItemValues); + // IBuffer buffer = CryptographicBuffer.DecodeFromBase64String(historyData); + + // if (buffer == null) + // { + // throw new Platform.Exception(E_POINTER, "History Item is NULL"); + // } + + // DataReader reader = DataReader.FromBuffer(buffer); + // var exprLen = reader.ReadUInt32(); + // var expression = reader.ReadString(exprLen); + // historyItem.historyItemVector.expression = expression.Data(); + + // var resultLen = reader.ReadUInt32(); + // var result = reader.ReadString(resultLen); + // historyItem.historyItemVector.result = result.Data(); + + // historyItem.historyItemVector.spCommands = Utils.DeserializeCommands(reader); + // historyItem.historyItemVector.spTokens = Utils.DeserializeTokens(reader); + //} + //else + //{ + // throw new Platform.Exception(E_ACCESSDENIED, "History Item not found"); + //} + //return historyItem; + throw new NotImplementedException(); + } + + bool IsValid(CalculationManager.HISTORYITEM item) + { + return + !string.IsNullOrEmpty(item.historyItemVector.expression) + && !string.IsNullOrEmpty(item.historyItemVector.result) + && item.historyItemVector.spCommands != null + && item.historyItemVector.spTokens != null; + } + + void UpdateItemSize() + { + ItemSize = Items.Count; + } + + void MakeHistoryClearedNarratorAnnouncement(String resourceKey, String formatVariable) + { + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement(resourceKey, formatVariable); + + HistoryAnnouncement = CalculatorAnnouncement.GetHistoryClearedAnnouncement(announcement); + } + } + } +} diff --git a/src/Calculator.Shared/ViewModels/MemoryItemViewModel.cs b/src/Calculator.Shared/ViewModels/MemoryItemViewModel.cs new file mode 100644 index 00000000..38dcffbb --- /dev/null +++ b/src/Calculator.Shared/ViewModels/MemoryItemViewModel.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; +using Windows.UI.Xaml.Data; + +namespace CalculatorApp +{ + namespace ViewModel + { + /// + /// Model representation of a single item in the Memory list + /// + [Windows.UI.Xaml.Data.Bindable] + public sealed class MemoryItemViewModel : INotifyPropertyChanged, Windows.UI.Xaml.Data.ICustomPropertyProvider + { + private StandardCalculatorViewModel m_calcVM; + + public MemoryItemViewModel(StandardCalculatorViewModel calcVM) + { + m_Position = -1; + m_calcVM = calcVM; + } + + public event PropertyChangedEventHandler PropertyChanged; + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); + private int m_Position; + public int Position { get => m_Position; set { m_Position = value; RaisePropertyChanged("Position"); } } + + private string m_Value; + public string Value { get => m_Value; set { m_Value = value; RaisePropertyChanged("Value"); } } + + public ICustomProperty GetCustomProperty(string name) { return null; } + + public ICustomProperty GetIndexedProperty(string name, Type type) { return null; } + + public Type Type + { + get + { + return this.GetType(); + } + } + + public string GetStringRepresentation() { return Value; } + + public void Clear() + { + m_calcVM.OnMemoryClear(Position); + } + + public void MemoryAdd() + { + m_calcVM.OnMemoryAdd(Position); + } + + public void MemorySubtract() + { + m_calcVM.OnMemorySubtract(Position); + } + + }; + } +} diff --git a/src/Calculator.Shared/ViewModels/StandardCalculatorViewModel.cs b/src/Calculator.Shared/ViewModels/StandardCalculatorViewModel.cs new file mode 100644 index 00000000..b215c6a6 --- /dev/null +++ b/src/Calculator.Shared/ViewModels/StandardCalculatorViewModel.cs @@ -0,0 +1,2438 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using CalculatorApp; +using CalculatorApp.Common; +using CalculatorApp.Common.Automation; +using CalculatorApp.ViewModel; +using CalculationManager; +using Windows.ApplicationModel.Resources; +using Windows.Foundation; +using Windows.System; +using Windows.UI.Core; +using Windows.UI.Popups; +using Windows.Storage.Streams; +using Windows.Foundation.Collections; +using static CalculatorApp.Utils; +using System; +using System.ComponentModel; +using System.Windows.Input; +using System.Collections.Generic; +using static CalculationManager.CCommand; +using System.Text; +using System.Linq; +using System.Collections.ObjectModel; +using System.Threading.Tasks; + +namespace CalculatorApp.ViewModel +{ + public class StandardCalculatorViewModel : INotifyPropertyChanged + { + public delegate void HideMemoryClickedHandler(); + public delegate void ProgModeRadixChangeHandler(); + + const int ASCII_0 = 48; + const int StandardModePrecision = 16; + const int ScientificModePrecision = 32; + const int ProgrammerModePrecision = 64; + + const string IsStandardPropertyName = "IsStandard"; + const string IsScientificPropertyName = "IsScientific"; + const string IsProgrammerPropertyName = "IsProgrammer"; + const string DisplayValuePropertyName = "DisplayValue"; + const string CalculationResultAutomationNamePropertyName = "CalculationResultAutomationName"; + + const string CalculatorExpression = "Format_CalculatorExpression"; + const string CalculatorResults = "Format_CalculatorResults"; + const string CalculatorResults_DecimalSeparator_Announced = "Format_CalculatorResults_Decimal"; + const string HexButton = "Format_HexButtonValue"; + const string DecButton = "Format_DecButtonValue"; + const string OctButton = "Format_OctButtonValue"; + const string BinButton = "Format_BinButtonValue"; + const string OpenParenthesisCountAutomationFormat = "Format_OpenParenthesisCountAutomationNamePix"; + const string NoParenthesisAdded = "NoRightParenthesisAdded_Announcement"; + const string MaxDigitsReachedFormat = "Format_MaxDigitsReached"; + const string ButtonPressFeedbackFormat = "Format_ButtonPressAuditoryFeedback"; + const string MemorySave = "Format_MemorySave"; + const string MemoryItemChanged = "Format_MemorySlotChanged"; + const string MemoryItemCleared = "Format_MemorySlotCleared"; + const string MemoryCleared = "Memory_Cleared"; + const string DisplayCopied = "Display_Copied"; + + public event HideMemoryClickedHandler HideMemoryClicked; + public event ProgModeRadixChangeHandler ProgModeRadixChange; + + public event PropertyChangedEventHandler PropertyChanged; + + private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string p = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p)); OnPropertyChanged(p); } + private string m_DisplayValue; + public string DisplayValue { get => m_DisplayValue; set { m_DisplayValue = value; RaisePropertyChanged("DisplayValue"); } } + + + private HistoryViewModel m_HistoryVM; + public HistoryViewModel HistoryVM { get => m_HistoryVM; set { m_HistoryVM = value; RaisePropertyChanged("HistoryVM"); } } + + + private const string IsInErrorName = "IsInError"; + private bool m_IsInError; + public bool IsInError { get => m_IsInError; set { m_IsInError = value; RaisePropertyChanged("IsInError"); } } + + + private bool m_IsOperatorCommand; + public bool IsOperatorCommand { get => m_IsOperatorCommand; set { m_IsOperatorCommand = value; RaisePropertyChanged("IsOperatorCommand"); } } + + + private string m_DisplayStringExpression; + public string DisplayStringExpression { get => m_DisplayStringExpression; set { m_DisplayStringExpression = value; RaisePropertyChanged("DisplayStringExpression"); } } + + + private ObservableCollection m_ExpressionTokens; + public ObservableCollection ExpressionTokens { get => m_ExpressionTokens; private set { m_ExpressionTokens = value; RaisePropertyChanged("ExpressionTokens"); } } + + + private string m_DecimalDisplayValue; + public string DecimalDisplayValue { get => m_DecimalDisplayValue; set { m_DecimalDisplayValue = value; RaisePropertyChanged("DecimalDisplayValue"); } } + + + private string m_HexDisplayValue; + public string HexDisplayValue { get => m_HexDisplayValue; set { m_HexDisplayValue = value; RaisePropertyChanged("HexDisplayValue"); } } + + + private string m_OctalDisplayValue; + public string OctalDisplayValue { get => m_OctalDisplayValue; set { m_OctalDisplayValue = value; RaisePropertyChanged("OctalDisplayValue"); } } + + + private const string BinaryDisplayValueName = "BinaryDisplayValue"; + private string m_BinaryDisplayValue; + public string BinaryDisplayValue { get => m_BinaryDisplayValue; set { m_BinaryDisplayValue = value; RaisePropertyChanged("BinaryDisplayValue"); } } + + + private string m_HexDisplayValue_AutomationName; + public string HexDisplayValue_AutomationName { get => m_HexDisplayValue_AutomationName; set { m_HexDisplayValue_AutomationName = value; RaisePropertyChanged("HexDisplayValue_AutomationName"); } } + + + private string m_DecDisplayValue_AutomationName; + public string DecDisplayValue_AutomationName { get => m_DecDisplayValue_AutomationName; set { m_DecDisplayValue_AutomationName = value; RaisePropertyChanged("DecDisplayValue_AutomationName"); } } + + + private string m_OctDisplayValue_AutomationName; + public string OctDisplayValue_AutomationName { get => m_OctDisplayValue_AutomationName; set { m_OctDisplayValue_AutomationName = value; RaisePropertyChanged("OctDisplayValue_AutomationName"); } } + + + private string m_BinDisplayValue_AutomationName; + public string BinDisplayValue_AutomationName { get => m_BinDisplayValue_AutomationName; set { m_BinDisplayValue_AutomationName = value; RaisePropertyChanged("BinDisplayValue_AutomationName"); } } + + + private bool m_IsBinaryOperatorEnabled; + public bool IsBinaryOperatorEnabled { get => m_IsBinaryOperatorEnabled; set { m_IsBinaryOperatorEnabled = value; RaisePropertyChanged("IsBinaryOperatorEnabled"); } } + + + private bool m_IsUnaryOperatorEnabled; + public bool IsUnaryOperatorEnabled { get => m_IsUnaryOperatorEnabled; set { m_IsUnaryOperatorEnabled = value; RaisePropertyChanged("IsUnaryOperatorEnabled"); } } + + + private bool m_IsNegateEnabled; + public bool IsNegateEnabled { get => m_IsNegateEnabled; set { m_IsNegateEnabled = value; RaisePropertyChanged("IsNegateEnabled"); } } + + + private bool m_IsDecimalEnabled; + public bool IsDecimalEnabled { get => m_IsDecimalEnabled; set { m_IsDecimalEnabled = value; RaisePropertyChanged("IsDecimalEnabled"); } } + + + private bool m_IsCurrentViewPinned; + public bool IsCurrentViewPinned { get => m_IsCurrentViewPinned; set { m_IsCurrentViewPinned = value; RaisePropertyChanged("IsCurrentViewPinned"); } } + + + private List m_MemorizedNumbers; + public List MemorizedNumbers { get => m_MemorizedNumbers; set { m_MemorizedNumbers = value; RaisePropertyChanged("MemorizedNumbers"); } } + + + private const string IsMemoryEmptyName = "IsMemoryEmpty"; + private bool m_IsMemoryEmpty; + public bool IsMemoryEmpty { get => m_IsMemoryEmpty; set { m_IsMemoryEmpty = value; RaisePropertyChanged("IsMemoryEmpty"); } } + + + private bool m_IsFToEChecked; + public bool IsFToEChecked { get => m_IsFToEChecked; set { m_IsFToEChecked = value; RaisePropertyChanged("IsFToEChecked"); } } + + + private bool m_IsFToEEnabled; + public bool IsFToEEnabled { get => m_IsFToEEnabled; set { m_IsFToEEnabled = value; RaisePropertyChanged("IsFToEEnabled"); } } + + + private bool m_IsHyperbolicChecked; + public bool IsHyperbolicChecked { get => m_IsHyperbolicChecked; set { m_IsHyperbolicChecked = value; RaisePropertyChanged("IsHyperbolicChecked"); } } + + + private bool m_AreHEXButtonsEnabled; + public bool AreHEXButtonsEnabled { get => m_AreHEXButtonsEnabled; set { m_AreHEXButtonsEnabled = value; RaisePropertyChanged("AreHEXButtonsEnabled"); } } + + + private string m_CalculationResultAutomationName; + public string CalculationResultAutomationName { get => m_CalculationResultAutomationName; set { m_CalculationResultAutomationName = value; RaisePropertyChanged("CalculationResultAutomationName"); } } + + + private string m_CalculationExpressionAutomationName; + public string CalculationExpressionAutomationName { get => m_CalculationExpressionAutomationName; set { m_CalculationExpressionAutomationName = value; RaisePropertyChanged("CalculationExpressionAutomationName"); } } + + + private bool m_IsShiftProgrammerChecked; + public bool IsShiftProgrammerChecked { get => m_IsShiftProgrammerChecked; set { m_IsShiftProgrammerChecked = value; RaisePropertyChanged("IsShiftProgrammerChecked"); } } + + + private bool m_IsQwordEnabled; + public bool IsQwordEnabled { get => m_IsQwordEnabled; set { m_IsQwordEnabled = value; RaisePropertyChanged("IsQwordEnabled"); } } + + + private bool m_IsDwordEnabled; + public bool IsDwordEnabled { get => m_IsDwordEnabled; set { m_IsDwordEnabled = value; RaisePropertyChanged("IsDwordEnabled"); } } + + + private bool m_IsWordEnabled; + public bool IsWordEnabled { get => m_IsWordEnabled; set { m_IsWordEnabled = value; RaisePropertyChanged("IsWordEnabled"); } } + + + private bool m_IsByteEnabled; + public bool IsByteEnabled { get => m_IsByteEnabled; set { m_IsByteEnabled = value; RaisePropertyChanged("IsByteEnabled"); } } + + + private RADIX_TYPE m_CurrentRadixType; + public RADIX_TYPE CurrentRadixType { get => m_CurrentRadixType; set { m_CurrentRadixType = value; RaisePropertyChanged("CurrentRadixType"); } } + + + private bool m_AreTokensUpdated; + public bool AreTokensUpdated { get => m_AreTokensUpdated; set { m_AreTokensUpdated = value; RaisePropertyChanged("AreTokensUpdated"); } } + + + private bool m_AreHistoryShortcutsEnabled; + public bool AreHistoryShortcutsEnabled { get => m_AreHistoryShortcutsEnabled; set { m_AreHistoryShortcutsEnabled = value; RaisePropertyChanged("AreHistoryShortcutsEnabled"); } } + + + private bool m_AreProgrammerRadixOperatorsEnabled; + public bool AreProgrammerRadixOperatorsEnabled { get => m_AreProgrammerRadixOperatorsEnabled; set { m_AreProgrammerRadixOperatorsEnabled = value; RaisePropertyChanged("AreProgrammerRadixOperatorsEnabled"); } } + + + private CalculatorApp.Common.Automation.NarratorAnnouncement m_Announcement; + public CalculatorApp.Common.Automation.NarratorAnnouncement Announcement { get => m_Announcement; set { m_Announcement = value; RaisePropertyChanged("Announcement"); } } + + + private int m_OpenParenthesisCount; + public int OpenParenthesisCount { get => m_OpenParenthesisCount; private set { m_OpenParenthesisCount = value; RaisePropertyChanged("OpenParenthesisCount"); } } + + public ICommand CopyCommand { get; } + + public ICommand PasteCommand { get; } + + public ICommand ButtonPressed { get; } + + public ICommand ClearMemoryCommand { get; } + + public ICommand MemoryItemPressed { get; } + + public ICommand MemoryAdd { get; } + + public ICommand MemorySubtract { get; } + + public bool IsShiftChecked + { + get + { + return m_isShiftChecked; + } + set + { + if (m_isShiftChecked != value) + { + m_isShiftChecked = value; + RaisePropertyChanged("IsShiftChecked"); + } + } + } + + public bool IsBitFlipChecked + { + get + { + return m_isBitFlipChecked; + } + set + { + if (m_isBitFlipChecked != value) + { + m_isBitFlipChecked = value; + IsBinaryBitFlippingEnabled = IsProgrammer && m_isBitFlipChecked; + AreProgrammerRadixOperatorsEnabled = IsProgrammer && !m_isBitFlipChecked; + RaisePropertyChanged("IsBitFlipChecked"); + } + } + } + + public bool IsBinaryBitFlippingEnabled + { + get + { + return m_isBinaryBitFlippingEnabled; + } + set + { + if (m_isBinaryBitFlippingEnabled != value) + { + m_isBinaryBitFlippingEnabled = value; + RaisePropertyChanged("IsBinaryBitFlippingEnabled"); + } + } + } + + public bool IsStandard + { + get + { + return m_isStandard; + } + set + { + if (m_isStandard != value) + { + m_isStandard = value; + if (value) + { + IsScientific = false; + IsProgrammer = false; + } + RaisePropertyChanged("IsStandard"); + } + } + } + public bool IsScientific + { + get + { + return m_isScientific; + } + set + { + if (m_isScientific != value) + { + m_isScientific = value; + if (value) + { + IsStandard = false; + IsProgrammer = false; + } + RaisePropertyChanged("IsScientific"); + } + } + } + + public bool IsProgrammer + { + get + { + return m_isProgrammer; + } + set + { + if (m_isProgrammer != value) + { + m_isProgrammer = value; + if (!m_isProgrammer) + { + IsBitFlipChecked = false; + } + IsBinaryBitFlippingEnabled = m_isProgrammer && IsBitFlipChecked; + AreProgrammerRadixOperatorsEnabled = m_isProgrammer && !IsBitFlipChecked; + if (value) + { + IsStandard = false; + IsScientific = false; + } + RaisePropertyChanged("IsProgrammer"); + } + } + } + + bool IsEditingEnabled + { + get + { + return m_isEditingEnabled; + } + set + { + if (m_isEditingEnabled != value) + { + // Numbers.Common.KeyboardShortcutManager.IsCalculatorInEditingMode = value; + m_isEditingEnabled = value; + bool currentEditToggleValue = !m_isEditingEnabled; + IsBinaryOperatorEnabled = currentEditToggleValue; + IsUnaryOperatorEnabled = currentEditToggleValue; + IsOperandEnabled = currentEditToggleValue; + IsNegateEnabled = currentEditToggleValue; + IsDecimalEnabled = currentEditToggleValue; + RaisePropertyChanged("IsEditingEnabled"); + } + } + } + + bool IsEngineRecording + { + get + { + return m_standardCalculatorManager.IsEngineRecording(); + } + } + + bool IsOperandEnabled + { + get + { + return m_isOperandEnabled; + } + set + { + if (m_isOperandEnabled != value) + { + m_isOperandEnabled = value; + IsDecimalEnabled = value; + AreHEXButtonsEnabled = IsProgrammer; + IsFToEEnabled = value; + RaisePropertyChanged("IsOperandEnabled"); + } + } + } + + int TokenPosition + { + get + { + return m_tokenPosition; + } + set + { + m_tokenPosition = value; + } + } + + string SelectedExpressionLastData + { + get { return m_selectedExpressionLastData; } + set { m_selectedExpressionLastData = value; } + } + + bool KeyPressed + { + get + { + return m_keyPressed; + } + set + { + m_keyPressed = value; + } + } + + bool IsOperandUpdatedUsingViewModel + { + get + { + return m_operandUpdated; + } + set + { + m_operandUpdated = value; + } + } + + bool IsOperandTextCompletelySelected + { + get + { + return m_completeTextSelection; + } + set + { + m_completeTextSelection = value; + } + } + + public RADIX_TYPE GetCurrentRadixType() => m_CurrentRadixType; + + void UpdateMaxIntDigits() => m_standardCalculatorManager.UpdateMaxIntDigits(); + + NumbersAndOperatorsEnum GetCurrentAngleType() => m_CurrentAngleType; + + // + // + // + + private NumbersAndOperatorsEnum m_CurrentAngleType; + private char m_decimalSeparator; + private CalculatorDisplay m_calculatorDisplay; + private EngineResourceProvider m_resourceProvider; + private CalculatorManager m_standardCalculatorManager; + private string m_expressionAutomationNameFormat; + private string m_localizedCalculationResultAutomationFormat; + private string m_localizedCalculationResultDecimalAutomationFormat; + private string m_localizedHexaDecimalAutomationFormat; + private string m_localizedDecimalAutomationFormat; + private string m_localizedOctalAutomationFormat; + private string m_localizedBinaryAutomationFormat; + private string m_localizedMaxDigitsReachedAutomationFormat; + private string m_localizedButtonPressFeedbackAutomationFormat; + private string m_localizedMemorySavedAutomationFormat; + private string m_localizedMemoryItemChangedAutomationFormat; + private string m_localizedMemoryItemClearedAutomationFormat; + private string m_localizedMemoryCleared; + private string m_localizedOpenParenthesisCountChangedAutomationFormat; + private string m_localizedNoRightParenthesisAddedFormat; + + private bool m_pinned; + private bool m_isOperandEnabled; + private bool m_isEditingEnabled; + private bool m_isStandard; + private bool m_isScientific; + private bool m_isProgrammer; + private bool m_isBinaryBitFlippingEnabled; + private bool m_isBitFlipChecked; + private bool m_isShiftChecked; + private bool m_isRtlLanguage; + private int m_tokenPosition; + private bool m_keyPressed; + private bool m_operandUpdated; + private bool m_completeTextSelection; + private bool m_isLastOperationHistoryLoad; + private string m_selectedExpressionLastData; + private DisplayExpressionToken m_selectedExpressionToken; + string m_feedbackForButtonPress; + + CalculatorList<(string, int)> m_tokens; + CalculatorList m_commands; + + public StandardCalculatorViewModel() + { + m_DisplayValue = "0"; + m_DecimalDisplayValue = "0"; + m_HexDisplayValue = "0"; + m_BinaryDisplayValue = "0"; + m_OctalDisplayValue = "0"; + m_standardCalculatorManager = new CalculatorManager(ref m_calculatorDisplay, ref m_resourceProvider); + m_ExpressionTokens = new ObservableCollection(); + m_MemorizedNumbers = new List(); + m_IsMemoryEmpty = true; + m_IsFToEChecked = false; + m_isShiftChecked = false; + m_IsShiftProgrammerChecked = false; + m_IsQwordEnabled = true; + m_IsDwordEnabled = true; + m_IsWordEnabled = true; + m_IsByteEnabled = true; + m_isBitFlipChecked = false; + m_isBinaryBitFlippingEnabled = false; + m_CurrentRadixType = RADIX_TYPE.DEC_RADIX; + m_CurrentAngleType = NumbersAndOperatorsEnum.Degree; + m_Announcement = null; + m_OpenParenthesisCount = 0; + m_feedbackForButtonPress = null; + m_isRtlLanguage = false; + m_localizedMaxDigitsReachedAutomationFormat = null; + m_localizedButtonPressFeedbackAutomationFormat = null; + m_localizedMemorySavedAutomationFormat = null; + m_localizedMemoryItemChangedAutomationFormat = null; + m_localizedMemoryItemClearedAutomationFormat = null; + m_localizedMemoryCleared = null; + m_localizedOpenParenthesisCountChangedAutomationFormat = null; + m_localizedNoRightParenthesisAddedFormat = null; + + CopyCommand = new DelegateCommand(OnCopyCommand); + PasteCommand = new DelegateCommand(OnPasteCommand); + ButtonPressed = new DelegateCommand(OnButtonPressed); + ClearMemoryCommand = new DelegateCommand(OnClearMemoryCommand); + MemoryItemPressed = new DelegateCommand(OnMemoryItemPressed); + MemoryAdd = new DelegateCommand(OnMemoryAdd); + MemorySubtract = new DelegateCommand(OnMemorySubtract); + + m_calculatorDisplay.SetCallback(new WeakReference(this)); + m_expressionAutomationNameFormat = AppResourceProvider.GetInstance().GetResourceString(CalculatorExpression); + m_localizedCalculationResultAutomationFormat = AppResourceProvider.GetInstance().GetResourceString(CalculatorResults); + m_localizedCalculationResultDecimalAutomationFormat = + AppResourceProvider.GetInstance().GetResourceString(CalculatorResults_DecimalSeparator_Announced); + m_localizedHexaDecimalAutomationFormat = AppResourceProvider.GetInstance().GetResourceString(HexButton); + m_localizedDecimalAutomationFormat = AppResourceProvider.GetInstance().GetResourceString(DecButton); + m_localizedOctalAutomationFormat = AppResourceProvider.GetInstance().GetResourceString(OctButton); + m_localizedBinaryAutomationFormat = AppResourceProvider.GetInstance().GetResourceString(BinButton); + + // Initialize the Automation Name + CalculationResultAutomationName = GetLocalizedStringFormat(m_localizedCalculationResultAutomationFormat, m_DisplayValue); + CalculationExpressionAutomationName = GetLocalizedStringFormat(m_expressionAutomationNameFormat, ""); + + // Initialize history view model + m_HistoryVM = new HistoryViewModel(m_standardCalculatorManager); + m_HistoryVM.SetCalculatorDisplay(m_calculatorDisplay); + + m_decimalSeparator = LocalizationSettings.GetInstance().GetDecimalSeparator(); + + if (CoreWindow.GetForCurrentThread() != null) + { + // Must have a CoreWindow to access the resource context. + m_isRtlLanguage = LocalizationService.GetInstance().IsRtlLayout(); + } + + IsEditingEnabled = false; + IsUnaryOperatorEnabled = true; + IsBinaryOperatorEnabled = true; + IsOperandEnabled = true; + IsNegateEnabled = true; + IsDecimalEnabled = true; + AreHistoryShortcutsEnabled = true; + AreProgrammerRadixOperatorsEnabled = false; + + m_tokenPosition = -1; + m_isLastOperationHistoryLoad = false; + } + + String LocalizeDisplayValue(string displayValue, bool isError) + { + string result = displayValue; + + LocalizationSettings.GetInstance().LocalizeDisplayValue(ref result); + + // WINBLUE: 440747 - In BiDi languages, error messages need to be wrapped in LRE/PDF + if (isError && m_isRtlLanguage) + { + result = Utils.LRE + result + Utils.PDF; + } + + return result; + } + + String CalculateNarratorDisplayValue(string displayValue, String localizedDisplayValue, bool isError) + { + String localizedValue = localizedDisplayValue; + String varmationFormat = m_localizedCalculationResultAutomationFormat; + + // The narrator doesn't read the decimalSeparator if it's the last character + if (Utils.IsLastCharacterTarget(displayValue, m_decimalSeparator)) + { + // remove the decimal separator, to avoid a long pause between words + localizedValue = LocalizeDisplayValue(displayValue.Substring(0, displayValue.Length - 1), isError); + + // Use a format which has a word in the decimal separator's place + // "The Display is 10 point" + varmationFormat = m_localizedCalculationResultDecimalAutomationFormat; + } + + // In Programmer modes using non-base10, we want the strings to be read as literal digits. + if (IsProgrammer && CurrentRadixType != RADIX_TYPE.DEC_RADIX) + { + localizedValue = GetNarratorStringReadRawNumbers(localizedValue); + } + + return GetLocalizedStringFormat(varmationFormat, localizedValue); + } + + String GetNarratorStringReadRawNumbers(String localizedDisplayValue) + { + StringBuilder wss = new StringBuilder(); + var locSettings = LocalizationSettings.GetInstance(); + + // Insert a space after each digit in the string, to force Narrator to read them as separate numbers. + string wstrValue = localizedDisplayValue; + foreach (char c in wstrValue) + { + wss.Append(c); + if (locSettings.IsLocalizedHexDigit(c)) + { + wss.Append(' '); + } + } + + return wss.ToString(); + } + + public void SetPrimaryDisplay(string displayStringValue, bool isError) + { + String localizedDisplayStringValue = LocalizeDisplayValue(displayStringValue, isError); + + // Set this variable before the DisplayValue is modified, Otherwise the DisplayValue will + // not match what the narrator is saying + m_CalculationResultAutomationName = CalculateNarratorDisplayValue(displayStringValue, localizedDisplayStringValue, isError); + + DisplayValue = localizedDisplayStringValue; + + IsInError = isError; + + if (IsProgrammer) + { + UpdateProgrammerPanelDisplay(); + } + } + + void DisplayPasteError() + { + m_standardCalculatorManager.DisplayPasteError(); + } + + public void SetParenthesisCount(int parenthesisCount) + { + if (m_OpenParenthesisCount == parenthesisCount) + { + return; + } + + OpenParenthesisCount = parenthesisCount; + if (IsProgrammer || IsScientific) + { + SetOpenParenthesisCountNarratorAnnouncement(); + } + } + + public void SetOpenParenthesisCountNarratorAnnouncement() + { + string localizedParenthesisCount = m_OpenParenthesisCount.ToString(); + LocalizationSettings.GetInstance().LocalizeDisplayValue(ref localizedParenthesisCount); + + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement( + OpenParenthesisCountAutomationFormat, + m_localizedOpenParenthesisCountChangedAutomationFormat, + localizedParenthesisCount); + + Announcement = CalculatorAnnouncement.GetOpenParenthesisCountChangedAnnouncement(announcement); + } + + public void OnNoRightParenAdded() + { + SetNoParenAddedNarratorAnnouncement(); + } + + void SetNoParenAddedNarratorAnnouncement() + { + String announcement = + LocalizationStringUtil.GetLocalizedNarratorAnnouncement(NoParenthesisAdded, m_localizedNoRightParenthesisAddedFormat); + + Announcement = CalculatorAnnouncement.GetNoRightParenthesisAddedAnnouncement(announcement); + } + + void DisableButtons(CommandType selectedExpressionCommandType) + { + if (selectedExpressionCommandType == CommandType.OperandCommand) + { + IsBinaryOperatorEnabled = false; + IsUnaryOperatorEnabled = false; + IsOperandEnabled = true; + IsNegateEnabled = true; + IsDecimalEnabled = true; + } + if (selectedExpressionCommandType == CommandType.BinaryCommand) + { + IsBinaryOperatorEnabled = true; + IsUnaryOperatorEnabled = false; + IsOperandEnabled = false; + IsNegateEnabled = false; + IsDecimalEnabled = false; + } + if (selectedExpressionCommandType == CommandType.UnaryCommand) + { + IsBinaryOperatorEnabled = false; + IsUnaryOperatorEnabled = true; + IsOperandEnabled = false; + IsNegateEnabled = true; + IsDecimalEnabled = false; + } + } + + public void SetExpressionDisplay( + CalculatorList<(string, int)> tokens, + CalculatorList commands) + { + m_tokens = tokens; + m_commands = commands; + if (!IsEditingEnabled) + { + SetTokens(tokens); + } + + CalculationExpressionAutomationName = GetCalculatorExpressionAutomationName(); + + AreTokensUpdated = true; + } + + public void SetHistoryExpressionDisplay( + CalculatorList<(string, int)> tokens, + CalculatorList commands) + { + m_tokens = new CalculatorList<(string, int)>(tokens); + m_commands = new CalculatorList(commands); + IsEditingEnabled = false; + + // Setting the History Item Load Mode so that UI does not get updated with recalculation of every token + m_standardCalculatorManager.SetInHistoryItemLoadMode(true); + Recalculate(true); + m_standardCalculatorManager.SetInHistoryItemLoadMode(false); + m_isLastOperationHistoryLoad = true; + } + + void SetTokens(CalculatorList<(string, int)> tokens) + { + AreTokensUpdated = false; + + int nTokens = 0; + tokens.GetSize(out nTokens); + + if (nTokens == 0) + { + m_ExpressionTokens.Clear(); + return; + } + + (string, int) currentToken; + var localizer = LocalizationSettings.GetInstance(); + + const string separator = " "; + for (int i = 0; i < nTokens; ++i) + { + if ((tokens.GetAt(i, out currentToken))) + { + Common.TokenType type; + bool isEditable = (currentToken.Item2 == -1) ? false : true; + localizer.LocalizeDisplayValue(ref currentToken.Item1); + + if (!isEditable) + { + type = currentToken.Item1 == separator ? TokenType.Separator : TokenType.Operator; + } + else + { + IExpressionCommand command; + IFTPlatformException(m_commands.GetAt(currentToken.Item2, out command)); + type = command.GetCommandType() == CommandType.OperandCommand ? TokenType.Operand : TokenType.Operator; + } + + var currentTokenString = currentToken.Item1; + if (i < m_ExpressionTokens.Count) + { + var existingItem = m_ExpressionTokens[i]; + if (type == existingItem.Type && existingItem.Token.Equals(currentTokenString)) + { + existingItem.TokenPosition = i; + existingItem.IsTokenEditable = isEditable; + existingItem.CommandIndex = 0; + } + else + { + var expressionToken = new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens.Insert(i, expressionToken); + } + } + else + { + var expressionToken = new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens.Append(expressionToken); + } + } + } + + while (m_ExpressionTokens.Count != nTokens) + { + m_ExpressionTokens.RemoveAt(m_ExpressionTokens.Count - 1); + } + } + + String GetCalculatorExpressionAutomationName() + { + String expression = ""; + foreach (var token in m_ExpressionTokens) + { + expression += LocalizationService.GetNarratorReadableToken(token.Token); + } + + return GetLocalizedStringFormat(m_expressionAutomationNameFormat, expression); + } + + public void SetMemorizedNumbers(List newMemorizedNumbers) + { + var localizer = LocalizationSettings.GetInstance(); + if (newMemorizedNumbers.Count == 0) // Memory has been cleared + { + MemorizedNumbers.Clear(); + IsMemoryEmpty = true; + } + // A new value is added to the memory + else if (newMemorizedNumbers.Count > MemorizedNumbers.Count) + { + while (newMemorizedNumbers.Count > MemorizedNumbers.Count) + { + int newValuePosition = newMemorizedNumbers.Count - MemorizedNumbers.Count - 1; + var stringValue = newMemorizedNumbers[newValuePosition]; + + MemoryItemViewModel memorySlot = new MemoryItemViewModel(this); + memorySlot.Position = 0; + localizer.LocalizeDisplayValue(ref stringValue); + memorySlot.Value = Utils.LRO + stringValue + Utils.PDF; + + MemorizedNumbers.Insert(0, memorySlot); + IsMemoryEmpty = false; + + // Update the slot position for the rest of the slots + for (int i = 1; i < MemorizedNumbers.Count; i++) + { + MemorizedNumbers[i].Position++; + } + } + } + else if (newMemorizedNumbers.Count == MemorizedNumbers.Count) // Either M+ or M- + { + for (int i = 0; i < MemorizedNumbers.Count; i++) + { + var newStringValue = newMemorizedNumbers[i]; + localizer.LocalizeDisplayValue(ref newStringValue); + + // If the value is different, update the value + if (MemorizedNumbers[i].Value != newStringValue) + { + MemorizedNumbers[i].Value = Utils.LRO + newStringValue + Utils.PDF; + } + } + } + } + + public void FtoEButtonToggled() + { + OnButtonPressed(NumbersAndOperatorsEnum.FToE); + } + + void HandleUpdatedOperandData(Command cmdenum) + { + DisplayExpressionToken displayExpressionToken = ExpressionTokens[m_tokenPosition]; + if (displayExpressionToken == null) + { + return; + } + if ((displayExpressionToken.Token == null) || (displayExpressionToken.Token.Length == 0)) + { + displayExpressionToken.CommandIndex = 0; + } + + char ch = '\0'; + if ((cmdenum >= Command.Command0) && (cmdenum <= Command.Command9)) + { + switch (cmdenum) + { + case Command.Command0: + ch = '0'; + break; + case Command.Command1: + ch = '1'; + break; + case Command.Command2: + ch = '2'; + break; + case Command.Command3: + ch = '3'; + break; + case Command.Command4: + ch = '4'; + break; + case Command.Command5: + ch = '5'; + break; + case Command.Command6: + ch = '6'; + break; + case Command.Command7: + ch = '7'; + break; + case Command.Command8: + ch = '8'; + break; + case Command.Command9: + ch = '9'; + break; + } + } + else if (cmdenum == Command.CommandPNT) + { + ch = '.'; + } + else if (cmdenum == Command.CommandBACK) + { + ch = 'x'; + } + else + { + return; + } + + int length = 0; + char[] temp = new char[100]; + char[] data = m_selectedExpressionLastData.ToCharArray(); + int i = 0, j = 0; + int commandIndex = displayExpressionToken.CommandIndex; + + if (IsOperandTextCompletelySelected) + { + // Clear older text; + m_selectedExpressionLastData = ""; + if (ch == 'x') + { + temp[0] = '\0'; + commandIndex = 0; + } + else + { + temp[0] = ch; + temp[1] = '\0'; + commandIndex = 1; + } + IsOperandTextCompletelySelected = false; + } + else + { + if (ch == 'x') + { + if (commandIndex == 0) + { + return; + } + + length = m_selectedExpressionLastData.Length; + for (; j < length; ++j) + { + if (j == commandIndex - 1) + { + continue; + } + temp[i++] = data[j]; + } + temp[i] = '\0'; + commandIndex -= 1; + } + else + { + length = m_selectedExpressionLastData.Length + 1; + if (length > 50) + { + return; + } + for (; i < length; ++i) + { + if (i == commandIndex) + { + temp[i] = ch; + continue; + } + temp[i] = data[j++]; + } + temp[i] = '\0'; + commandIndex += 1; + } + } + + String updatedData = new String(temp); + UpdateOperand(m_tokenPosition, updatedData); + displayExpressionToken.Token = updatedData; + IsOperandUpdatedUsingViewModel = true; + displayExpressionToken.CommandIndex = commandIndex; + } + + bool IsOperator(Command cmdenum) + { + if ((cmdenum >= Command.Command0 && cmdenum <= Command.Command9) || (cmdenum == Command.CommandPNT) || (cmdenum == Command.CommandBACK) + || (cmdenum == Command.CommandEXP) || (cmdenum == Command.CommandFE) || (cmdenum == Command.ModeBasic) || (cmdenum == Command.ModeProgrammer) + || (cmdenum == Command.ModeScientific) || (cmdenum == Command.CommandINV) || (cmdenum == Command.CommandCENTR) || (cmdenum == Command.CommandDEG) + || (cmdenum == Command.CommandRAD) || (cmdenum == Command.CommandGRAD) + || ((cmdenum >= Command.CommandBINEDITSTART) && (cmdenum <= Command.CommandBINEDITEND))) + { + return false; + } + return true; + } + + void OnButtonPressed(object parameter) + { + m_feedbackForButtonPress = CalculatorButtonPressedEventArgs.GetAuditoryFeedbackFromCommandParameter(parameter); + NumbersAndOperatorsEnum numOpEnum = CalculatorButtonPressedEventArgs.GetOperationFromCommandParameter(parameter); + Command cmdenum = ConvertToOperatorsEnum(numOpEnum); + + //TraceLogger.GetInstance().UpdateFunctionUsage((int)numOpEnum); + + if (IsInError) + { + m_standardCalculatorManager.SendCommand(Command.CommandCLEAR); + + if (!IsRecoverableCommand((int)numOpEnum)) + { + return; + } + } + + if (IsEditingEnabled && numOpEnum != NumbersAndOperatorsEnum.IsScientificMode && numOpEnum != NumbersAndOperatorsEnum.IsStandardMode + && numOpEnum != NumbersAndOperatorsEnum.IsProgrammerMode && numOpEnum != NumbersAndOperatorsEnum.FToE + && (numOpEnum != NumbersAndOperatorsEnum.Degree) && (numOpEnum != NumbersAndOperatorsEnum.Radians) && (numOpEnum != NumbersAndOperatorsEnum.Grads)) + { + if (!m_keyPressed) + { + SaveEditedCommand(m_selectedExpressionToken.TokenPosition, cmdenum); + } + } + else + { + if (numOpEnum == NumbersAndOperatorsEnum.IsStandardMode || numOpEnum == NumbersAndOperatorsEnum.IsScientificMode + || numOpEnum == NumbersAndOperatorsEnum.IsProgrammerMode) + { + IsEditingEnabled = false; + } + if (numOpEnum == NumbersAndOperatorsEnum.Memory) + { + OnMemoryButtonPressed(); + } + else + { + if (numOpEnum == NumbersAndOperatorsEnum.Clear || numOpEnum == NumbersAndOperatorsEnum.ClearEntry + || numOpEnum == NumbersAndOperatorsEnum.IsStandardMode || numOpEnum == NumbersAndOperatorsEnum.IsProgrammerMode) + { + // On Clear('C') the F-E button needs to be UnChecked if it in Checked state. + // Also, the Primary Display Value should not show in exponential format. + // Hence the check below to ensure parity with Desktop Calculator. + // Clear the FE mode if the switching to StandardMode, since 'C'/'CE' in StandardMode + // doesn't honor the FE button. + if (IsFToEChecked) + { + IsFToEChecked = false; + } + } + if (numOpEnum == NumbersAndOperatorsEnum.Degree || numOpEnum == NumbersAndOperatorsEnum.Radians || numOpEnum == NumbersAndOperatorsEnum.Grads) + { + m_CurrentAngleType = numOpEnum; + } + if ((cmdenum >= Command.Command0 && cmdenum <= Command.Command9) || (cmdenum == Command.CommandPNT) || (cmdenum == Command.CommandBACK) + || (cmdenum == Command.CommandEXP)) + { + IsOperatorCommand = false; + } + else + { + IsOperatorCommand = true; + } + + if (m_isLastOperationHistoryLoad + && ((numOpEnum != NumbersAndOperatorsEnum.Degree) && (numOpEnum != NumbersAndOperatorsEnum.Radians) + && (numOpEnum != NumbersAndOperatorsEnum.Grads))) + { + IsFToEEnabled = true; + m_isLastOperationHistoryLoad = false; + } + + m_standardCalculatorManager.SendCommand(cmdenum); + } + } + } + + int GetBitLengthType() + { + if (IsQwordEnabled) + { + return CopyPasteManager.QwordType; + } + else if (IsDwordEnabled) + { + return CopyPasteManager.DwordType; + } + else if (IsWordEnabled) + { + return CopyPasteManager.WordType; + } + else + { + return CopyPasteManager.ByteType; + } + } + + int GetNumberBase() + { + if (CurrentRadixType == RADIX_TYPE.HEX_RADIX) + { + return CopyPasteManager.HexBase; + } + else if (CurrentRadixType == RADIX_TYPE.DEC_RADIX) + { + return CopyPasteManager.DecBase; + } + else if (CurrentRadixType == RADIX_TYPE.OCT_RADIX) + { + return CopyPasteManager.OctBase; + } + else + { + return CopyPasteManager.BinBase; + } + } + + public void OnCopyCommand(object parameter) + { + CopyPasteManager.CopyToClipboard(GetRawDisplayValue()); + + String announcement = AppResourceProvider.GetInstance().GetResourceString(DisplayCopied); + Announcement = CalculatorAnnouncement.GetDisplayCopiedAnnouncement(announcement); + } + + public void OnPasteCommand(object parameter) + { + ViewMode mode; + int NumberBase = -1; + int bitLengthType = -1; + if (IsScientific) + { + mode = ViewMode.Scientific; + } + else if (IsProgrammer) + { + mode = ViewMode.Programmer; + NumberBase = GetNumberBase(); + bitLengthType = GetBitLengthType(); + } + else + { + mode = ViewMode.Standard; + } + // if there's nothing to copy early out + if (IsEditingEnabled || !CopyPasteManager.HasStringToPaste()) + { + return; + } + + // Ensure that the paste happens on the UI thread + CopyPasteManager.GetStringToPaste(mode, NavCategory.GetGroupType(mode), NumberBase, bitLengthType) + .ContinueWith(async (Task pastedString, object s) => { OnPaste(await pastedString, mode); }, null); + } + + CalculationManager.Command ConvertToOperatorsEnum(NumbersAndOperatorsEnum operation) + { + return (Command)(operation); + } + + void OnPaste(String pastedString, ViewMode mode) + { + // If pastedString is invalid("NoOp") then display pasteError else process the string + if (pastedString == CopyPasteManager.PasteErrorString) + { + this.DisplayPasteError(); + return; + } + + //TraceLogger.GetInstance().LogValidInputPasted(mode); + bool isFirstLegalChar = true; + m_standardCalculatorManager.SendCommand(Command.CommandCENTR); + bool sendNegate = false; + bool processedDigit = false; + bool sentEquals = false; + bool isPreviousOperator = false; + + List negateStack = new List(); + + // Iterate through each character pasted, and if it's valid, send it to the model. + var it = pastedString.GetEnumerator(); + + while (it.MoveNext()) + { + bool sendCommand = true; + bool canSendNegate = false; + + NumbersAndOperatorsEnum mappedNumOp = MapCharacterToButtonId(it.Current, canSendNegate); + + if (mappedNumOp == NumbersAndOperatorsEnum.None) + { + it.MoveNext(); + continue; + } + + if (isFirstLegalChar || isPreviousOperator) + { + isFirstLegalChar = false; + isPreviousOperator = false; + + // If the character is a - sign, send negate + // after sending the next legal character. Send nothing now, or + // it will be ignored. + if (NumbersAndOperatorsEnum.Subtract == mappedNumOp) + { + sendNegate = true; + sendCommand = false; + } + + // Support (+) sign pix + if (NumbersAndOperatorsEnum.Add == mappedNumOp) + { + sendCommand = false; + } + } + + switch (mappedNumOp) + { + // Opening parenthesis starts a new expression and pushes negation state onto the stack + case NumbersAndOperatorsEnum.OpenParenthesis: + negateStack.Add(sendNegate); + sendNegate = false; + break; + + // Closing parenthesis pops the negation state off the stack and sends it down to the calc engine + case NumbersAndOperatorsEnum.CloseParenthesis: + if (negateStack.Any()) + { + sendNegate = negateStack.Last(); + negateStack.RemoveAt(negateStack.Count - 1); + canSendNegate = true; + } + else + { + // Don't send a closing parenthesis if a matching opening parenthesis hasn't been sent already + sendCommand = false; + } + break; + + case NumbersAndOperatorsEnum.Zero: + case NumbersAndOperatorsEnum.One: + case NumbersAndOperatorsEnum.Two: + case NumbersAndOperatorsEnum.Three: + case NumbersAndOperatorsEnum.Four: + case NumbersAndOperatorsEnum.Five: + case NumbersAndOperatorsEnum.Six: + case NumbersAndOperatorsEnum.Seven: + case NumbersAndOperatorsEnum.Eight: + case NumbersAndOperatorsEnum.Nine: + processedDigit = true; + break; + + case NumbersAndOperatorsEnum.Add: + case NumbersAndOperatorsEnum.Subtract: + case NumbersAndOperatorsEnum.Multiply: + case NumbersAndOperatorsEnum.Divide: + isPreviousOperator = true; + break; + } + + if (sendCommand) + { + sentEquals = (mappedNumOp == NumbersAndOperatorsEnum.Equals); + Command cmdenum = ConvertToOperatorsEnum(mappedNumOp); + m_standardCalculatorManager.SendCommand(cmdenum); + + // The CalcEngine state machine won't allow the negate command to be sent before any + // other digits, so instead a flag is set and the command is sent after the first appropriate + // command. + if (sendNegate) + { + if (canSendNegate) + { + Command cmdNegate = ConvertToOperatorsEnum(NumbersAndOperatorsEnum.Negate); + m_standardCalculatorManager.SendCommand(cmdNegate); + } + + // Can't send negate on a leading zero, so wait until the appropriate time to send it. + if (NumbersAndOperatorsEnum.Zero != mappedNumOp && NumbersAndOperatorsEnum.Decimal != mappedNumOp) + { + sendNegate = false; + } + } + } + + // Handle exponent and exponent sign (...e+... or ...e-...) + if (mappedNumOp == NumbersAndOperatorsEnum.Exp) + { + it.MoveNext(); + if (!(MapCharacterToButtonId(it.Current, canSendNegate) == NumbersAndOperatorsEnum.Add)) + { + Command cmdNegate = ConvertToOperatorsEnum(NumbersAndOperatorsEnum.Negate); + m_standardCalculatorManager.SendCommand(cmdNegate); + } + } + } + } + + void OnClearMemoryCommand(object parameter) + { + m_standardCalculatorManager.MemorizedNumberClearAll(); + + int windowId = Utils.GetWindowId(); + //TraceLogger.GetInstance().LogMemoryClearAll(windowId); + + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement(MemoryCleared, m_localizedMemoryCleared); + Announcement = CalculatorAnnouncement.GetMemoryClearedAnnouncement(announcement); + } + + void OnPinUnpinCommand(object parameter) + { + SetViewPinnedState(!IsViewPinned()); + } + + bool IsViewPinned() + { + return m_IsCurrentViewPinned; + } + + void SetViewPinnedState(bool pinned) + { + IsCurrentViewPinned = pinned; + } + + NumbersAndOperatorsEnum MapCharacterToButtonId(char ch, bool canSendNegate) + { + NumbersAndOperatorsEnum mappedValue = NumbersAndOperatorsEnum.None; + canSendNegate = false; + + switch (ch) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + mappedValue = (int)NumbersAndOperatorsEnum.Zero + (NumbersAndOperatorsEnum)(ch - '0'); + canSendNegate = true; + break; + + case '*': + mappedValue = NumbersAndOperatorsEnum.Multiply; + break; + + case '+': + mappedValue = NumbersAndOperatorsEnum.Add; + break; + + case '-': + mappedValue = NumbersAndOperatorsEnum.Subtract; + break; + + case '/': + mappedValue = NumbersAndOperatorsEnum.Divide; + break; + + case '=': + mappedValue = NumbersAndOperatorsEnum.Equals; + break; + + case '(': + mappedValue = NumbersAndOperatorsEnum.OpenParenthesis; + break; + + case ')': + mappedValue = NumbersAndOperatorsEnum.CloseParenthesis; + break; + + case 'a': + case 'A': + mappedValue = NumbersAndOperatorsEnum.A; + break; + case 'b': + case 'B': + mappedValue = NumbersAndOperatorsEnum.B; + break; + case 'c': + case 'C': + mappedValue = NumbersAndOperatorsEnum.C; + break; + case 'd': + case 'D': + mappedValue = NumbersAndOperatorsEnum.D; + break; + case 'e': + case 'E': + // Only allow scientific notation in scientific mode + if (IsProgrammer) + { + mappedValue = NumbersAndOperatorsEnum.E; + } + else + { + mappedValue = NumbersAndOperatorsEnum.Exp; + } + break; + case 'f': + case 'F': + mappedValue = NumbersAndOperatorsEnum.F; + break; + default: + // For the decimalSeparator, we need to respect the user setting. + if (ch == m_decimalSeparator) + { + mappedValue = NumbersAndOperatorsEnum.Decimal; + } + break; + } + + if (mappedValue == NumbersAndOperatorsEnum.None) + { + if (LocalizationSettings.GetInstance().IsLocalizedDigit(ch)) + { + mappedValue = + NumbersAndOperatorsEnum.Zero + (int)(ch - LocalizationSettings.GetInstance().GetDigitSymbolFromEnUsDigit('0')); + canSendNegate = true; + } + } + + // Negate cannot be sent for leading zeroes + if (NumbersAndOperatorsEnum.Zero == mappedValue) + { + canSendNegate = false; + } + + return mappedValue; + } + + void OnMemoryButtonPressed() + { + m_standardCalculatorManager.MemorizeNumber(); + + int windowId = Utils.GetWindowId(); + //TraceLogger.GetInstance().InsertIntoMemoryMap(windowId, IsStandard, IsScientific, IsProgrammer); + + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement( + MemorySave, m_localizedMemorySavedAutomationFormat, m_DisplayValue); + + Announcement = CalculatorAnnouncement.GetMemoryItemAddedAnnouncement(announcement); + } + + public void OnMemoryItemChanged(int indexOfMemory) + { + if (indexOfMemory < MemorizedNumbers.Count) + { + MemoryItemViewModel memSlot = MemorizedNumbers[indexOfMemory]; + String localizedValue = memSlot.Value; + + string localizedIndex = (indexOfMemory + 1).ToString(); + LocalizationSettings.GetInstance().LocalizeDisplayValue(ref localizedIndex); + + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement( + MemoryItemChanged, m_localizedMemoryItemChangedAutomationFormat, localizedIndex, localizedValue); + + Announcement = CalculatorAnnouncement.GetMemoryItemChangedAnnouncement(announcement); + } + } + + void OnMemoryItemPressed(object memoryItemPosition) + { + if (MemorizedNumbers != null && MemorizedNumbers.Count > 0) + { + if (memoryItemPosition is int boxedPosition) + { + m_standardCalculatorManager.MemorizedNumberLoad(boxedPosition); + HideMemoryClicked(); + int windowId = Utils.GetWindowId(); + //TraceLogger.GetInstance().LogMemoryUsed(windowId, boxedPosition.Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers.Size); + } + } + } + + public void OnMemoryAdd(object memoryItemPosition) + { + // M+ will add display to memorylist if memory list is empty. + int windowId = Utils.GetWindowId(); + + if (MemorizedNumbers != null) + { + var boxedPosition = (int)(memoryItemPosition); + if (MemorizedNumbers.Count > 0) + { + //TraceLogger.GetInstance().LogMemoryUsed(windowId, boxedPosition.Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers.Size); + //TraceLogger.GetInstance().UpdateMemoryMap(windowId, boxedPosition.Value, IsStandard, IsScientific, IsProgrammer); + } + else + { + //TraceLogger.GetInstance().InsertIntoMemoryMap(windowId, IsStandard, IsScientific, IsProgrammer); + } + m_standardCalculatorManager.MemorizedNumberAdd(boxedPosition); + } + } + + public void OnMemorySubtract(object memoryItemPosition) + { + int windowId = Utils.GetWindowId(); + + // M- will add negative of displayed number to memorylist if memory list is empty. + if (MemorizedNumbers != null) + { + var boxedPosition = (int)(memoryItemPosition); + if (MemorizedNumbers.Count > 0) + { + //TraceLogger.GetInstance().LogMemoryUsed(windowId, boxedPosition.Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers.Size); + //TraceLogger.GetInstance().UpdateMemoryMap(windowId, boxedPosition.Value, IsStandard, IsScientific, IsProgrammer); + } + else + { + //TraceLogger.GetInstance().InsertIntoMemoryMap(windowId, IsStandard, IsScientific, IsProgrammer); + } + m_standardCalculatorManager.MemorizedNumberSubtract(boxedPosition); + } + } + + public void OnMemoryClear(object memoryItemPosition) + { + if (MemorizedNumbers != null && MemorizedNumbers.Count > 0) + { + int windowId = Utils.GetWindowId(); + var boxedPosition = (int)(memoryItemPosition); + + if (boxedPosition >= 0) + { + int unsignedPosition = boxedPosition; + m_standardCalculatorManager.MemorizedNumberClear(unsignedPosition); + + MemorizedNumbers.RemoveAt(unsignedPosition); + for (int i = 0; i < MemorizedNumbers.Count; i++) + { + MemorizedNumbers[i].Position = i; + } + + if (MemorizedNumbers.Count == 0) + { + IsMemoryEmpty = true; + } + + //TraceLogger.GetInstance().LogMemoryUsed(windowId, boxedPosition.Value, IsStandard, IsScientific, IsProgrammer, MemorizedNumbers.Size); + //TraceLogger.GetInstance().DeleteFromMemoryMap(windowId, boxedPosition.Value); + + string localizedIndex = (boxedPosition + 1).ToString(); + LocalizationSettings.GetInstance().LocalizeDisplayValue(ref localizedIndex); + + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement( + MemoryItemCleared, m_localizedMemoryItemClearedAutomationFormat, localizedIndex); + + Announcement = CalculatorAnnouncement.GetMemoryClearedAnnouncement(announcement); + } + } + } + + List Serialize() + { + //DataWriter writer = new DataWriter(); + //writer.Writeuint((uint)(m_CurrentAngleType)); + //writer.WriteBoolean(IsFToEChecked); + //writer.WriteBoolean(IsCurrentViewPinned); + //writer.Writeuint((uint)(m_standardCalculatorManager.SerializeSavedDegreeMode())); + + //// Serialize Memory + //List serializedMemory; + //serializedMemory = m_standardCalculatorManager.GetSerializedMemory(); + //int lengthOfSerializedMemory = serializedMemory.size(); + //writer.Writeuint((uint)(lengthOfSerializedMemory)); + //for (var data : serializedMemory) + //{ + // writer.WriteInt32(data); + //} + + //// Serialize Primary Display + //List serializedPrimaryDisplay = m_standardCalculatorManager.GetSerializedPrimaryDisplay(); + //writer.Writeuint((uint)(serializedPrimaryDisplay.size())); + //for (var data : serializedPrimaryDisplay) + //{ + // writer.WriteInt32(data); + //} + + //// For ProgrammerMode + //writer.Writeuint((uint)(CurrentRadixType)); + + //// Serialize commands of calculator manager + //vector < unsigned char> serializedCommand = m_standardCalculatorManager.SerializeCommands(); + //writer.Writeuint((uint)(serializedCommand.size())); + //writer.WriteBytes(new Array(serializedCommand.data(), (uint)(serializedCommand.size()))); + + //if (IsInError) + //{ + // Utils.SerializeCommandsAndTokens(m_tokens, m_commands, writer); + //} + + //// Convert viewmodel data in writer to bytes + //IBuffer buffer = writer.DetachBuffer(); + //DataReader reader = DataReader.FromBuffer(buffer); + //Platform.Array < unsigned char> viewModelDataAsBytes = new Array(buffer.Length); + //reader.ReadBytes(viewModelDataAsBytes); + + //// Return byte array + //return viewModelDataAsBytes; + + return null; + } + + void Deserialize(char[] state) + { + //// Read byte array into a buffer + //DataWriter writer = new DataWriter(); + //writer.WriteBytes(state); + //IBuffer buffer = writer.DetachBuffer(); + + //// Read view model data + //if (buffer.Length != 0) + //{ + // DataReader reader = DataReader.FromBuffer(buffer); + // m_CurrentAngleType = ConvertIntegerToNumbersAndOperatorsEnum(reader.Readuint()); + + // IsFToEChecked = reader.ReadBoolean(); + // IsCurrentViewPinned = reader.ReadBoolean(); + // Command serializedDegreeMode = (Command)(reader.Readuint()); + + // m_standardCalculatorManager.SendCommand(serializedDegreeMode); + + // // Deserialize Memory + // uint memoryDataLength = reader.Readuint(); + // List serializedMemory; + // for (uint i = 0; i < memoryDataLength; i++) + // { + // serializedMemory.push_back(reader.ReadInt32()); + // } + // m_standardCalculatorManager.DeSerializeMemory(serializedMemory); + + // // Serialize Primary Display + // uint serializedPrimaryDisplayLength = reader.Readuint(); + // List serializedPrimaryDisplay; + // for (uint i = 0; i < serializedPrimaryDisplayLength; i++) + // { + // serializedPrimaryDisplay.push_back(reader.ReadInt32()); + // } + // m_standardCalculatorManager.DeSerializePrimaryDisplay(serializedPrimaryDisplay); + + // CurrentRadixType = reader.Readuint(); + // // Read command data and Deserialize + // uint modeldatalength = reader.Readuint(); + // Array < unsigned char> modelDataAsBytes = new Array(modeldatalength); + // reader.ReadBytes(modelDataAsBytes); + // m_standardCalculatorManager.DeSerializeCommands(vector < unsigned char > (modelDataAsBytes.begin(), modelDataAsBytes.end())); + + // // After recalculation. If there is an error then + // // IsInError should be set synchronously. + // if (IsInError) + // { + // CalculatorList commandVector = Utils.DeserializeCommands(reader); + // CalculatorList<(string, int)> tokenVector = Utils.DeserializeTokens(reader); + // SetExpressionDisplay(tokenVector, commandVector); + // } + //} + } + + void OnPropertyChanged(String propertyname) + { + if (propertyname == IsScientificPropertyName) + { + if (IsScientific) + { + OnButtonPressed(NumbersAndOperatorsEnum.IsScientificMode); + } + } + else if (propertyname == IsProgrammerPropertyName) + { + if (IsProgrammer) + { + OnButtonPressed(NumbersAndOperatorsEnum.IsProgrammerMode); + } + } + else if (propertyname == IsStandardPropertyName) + { + if (IsStandard) + { + OnButtonPressed(NumbersAndOperatorsEnum.IsStandardMode); + } + } + else if (propertyname == DisplayValuePropertyName) + { + RaisePropertyChanged(CalculationResultAutomationNamePropertyName); + Announcement = GetDisplayUpdatedNarratorAnnouncement(); + } + } + + public void SetCalculatorType(ViewMode targetState) + { + // Reset error state so that commands caused by the mode change are still + // sent if calc is currently in error state. + IsInError = false; + + // Setting one of these properties to true will set the others to false. + switch (targetState) + { + case ViewMode.Standard: + IsStandard = true; + ResetDisplay(); + SetPrecision(StandardModePrecision); + UpdateMaxIntDigits(); + break; + + case ViewMode.Scientific: + IsScientific = true; + ResetDisplay(); + SetPrecision(ScientificModePrecision); + break; + + case ViewMode.Programmer: + IsProgrammer = true; + ResetDisplay(); + SetPrecision(ProgrammerModePrecision); + break; + } + } + + string GetRawDisplayValue() + { + string rawValue = null; + + LocalizationSettings.GetInstance().RemoveGroupSeparators(DisplayValue, DisplayValue.Length, ref rawValue); + + return rawValue; + } + + // Given a format string, returns a string with the input display value inserted. + // 'format' is a localized string containing a %1 formatting mark where the display value should be inserted. + // 'displayValue' is a localized string containing a numerical value to be displayed to the user. + String GetLocalizedStringFormat(String format, String displayValue) + { + String localizedString = LocalizationStringUtil.GetLocalizedString(format, displayValue); + return localizedString; + } + + void ResetDisplay() + { + AreHEXButtonsEnabled = false; + CurrentRadixType = RADIX_TYPE.DEC_RADIX; + m_standardCalculatorManager.SetRadix(RADIX_TYPE.DEC_RADIX); + ProgModeRadixChange?.Invoke(); + } + + void SetPrecision(int precision) + { + m_standardCalculatorManager.SetPrecision(precision); + } + + public void SwitchProgrammerModeBase(RADIX_TYPE radixType) + { + if (IsInError) + { + m_standardCalculatorManager.SendCommand(Command.CommandCLEAR); + } + + AreHEXButtonsEnabled = (radixType == RADIX_TYPE.HEX_RADIX); + CurrentRadixType = radixType; + m_standardCalculatorManager.SetRadix(radixType); + ProgModeRadixChange?.Invoke(); + } + + public void SetMemorizedNumbersString() + { + m_standardCalculatorManager.SetMemorizedNumbersString(); + } + + ANGLE_TYPE GetAngleTypeFromCommand(Command command) + { + switch (command) + { + case Command.CommandDEG: + return ANGLE_TYPE.ANGLE_DEG; + case Command.CommandRAD: + return ANGLE_TYPE.ANGLE_RAD; + case Command.CommandGRAD: + return ANGLE_TYPE.ANGLE_GRAD; + default: + throw new Exception("Invalid command type"); + } + } + + void SaveEditedCommand(int tokenPosition, Command command) + { + (string, int) token; + bool handleOperand = false; + int nOpCode = (int)(command); + string updatedToken = ""; + + IExpressionCommand tokenCommand; + IFTPlatformException(m_tokens.GetAt(tokenPosition, out token)); + + int tokenCommandIndex = token.Item2; + IFTPlatformException(m_commands.GetAt(tokenCommandIndex, out tokenCommand)); + + if (IsUnaryOp(nOpCode) && command != Command.CommandSIGN) + { + int angleCmd = (int)(m_standardCalculatorManager.GetCurrentDegreeMode()); + ANGLE_TYPE angleType = GetAngleTypeFromCommand((Command)(angleCmd)); + + if (IsTrigOp(nOpCode)) + { + IUnaryCommand spUnaryCommand = (IUnaryCommand)(tokenCommand); + spUnaryCommand.SetCommands(angleCmd, nOpCode); + } + else + { + IUnaryCommand spUnaryCommand = (IUnaryCommand)(tokenCommand); + spUnaryCommand.SetCommand(nOpCode); + } + + switch (nOpCode) + { + case (int)(Command.CommandASIN): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandSIN), true, angleType); + break; + case (int)(Command.CommandACOS): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandCOS), true, angleType); + break; + case (int)(Command.CommandATAN): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandTAN), true, angleType); + break; + case (int)(Command.CommandASINH): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandSINH), true, angleType); + break; + case (int)(Command.CommandACOSH): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandCOSH), true, angleType); + break; + case (int)(Command.CommandATANH): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandTANH), true, angleType); + break; + case (int)(Command.CommandPOWE): + updatedToken = CCalcEngine.OpCodeToUnaryString((int)(Command.CommandLN), true, angleType); + break; + default: + updatedToken = CCalcEngine.OpCodeToUnaryString(nOpCode, false, angleType); + break; + } + if ((token.Item1.Length > 0) && (token.Item1[token.Item1.Length - 1] == '(')) + { + string chOpenBrace = "("; + updatedToken += chOpenBrace; + } + } + else if (IsBinOp(nOpCode)) + { + IBinaryCommand spBinaryCommand = (IBinaryCommand)(tokenCommand); + spBinaryCommand.SetCommand(nOpCode); + updatedToken = CCalcEngine.OpCodeToString(nOpCode); + } + else if (IsOpnd(nOpCode) || command == Command.CommandBACK) + { + HandleUpdatedOperandData(command); + handleOperand = true; + } + else if (command == Command.CommandSIGN) + { + if (tokenCommand.GetCommandType() == CommandType.UnaryCommand) + { + IExpressionCommand spSignCommand = new CUnaryCommand(nOpCode); + IFTPlatformException(m_commands.InsertAt(tokenCommandIndex + 1, spSignCommand)); + } + else + { + IOpndCommand spOpndCommand = (IOpndCommand)(tokenCommand); + spOpndCommand.ToggleSign(); + updatedToken = spOpndCommand.GetToken(m_standardCalculatorManager.DecimalSeparator()); + } + IsOperandUpdatedUsingViewModel = true; + } + + if (!handleOperand) + { + IFTPlatformException(m_commands.SetAt(tokenCommandIndex, tokenCommand)); + + (string, int) selectedToken; + IFTPlatformException(m_tokens.GetAt(tokenPosition, out selectedToken)); + selectedToken.Item1 = updatedToken; + IFTPlatformException(m_tokens.SetAt(tokenPosition, selectedToken)); + + DisplayExpressionToken displayExpressionToken = ExpressionTokens[tokenPosition]; + displayExpressionToken.Token = updatedToken; + + // Special casing + if (command == Command.CommandSIGN && tokenCommand.GetCommandType() == CommandType.UnaryCommand) + { + IsEditingEnabled = false; + Recalculate(); + } + } + } + + void Recalculate(bool fromHistory = false) + { + // Recalculate + Command currentDegreeMode = m_standardCalculatorManager.GetCurrentDegreeMode(); + CalculatorList savedCommands = new CalculatorList(); + + List currentCommands = new List(); + int commandListCount; + m_commands.GetSize(out commandListCount); + for (int i = 0; i < commandListCount; i++) + { + IExpressionCommand command; + IFTPlatformException(m_commands.GetAt(i, out command)); + + savedCommands.Append(command); + CommandType commandType = command.GetCommandType(); + + if (commandType == CommandType.UnaryCommand) + { + IUnaryCommand spCommand = (IUnaryCommand)(command); + CalculatorList unaryCommands = spCommand.GetCommands(); + int unaryCommandCount; + unaryCommands.GetSize(out unaryCommandCount); + + int nUCode; + for (int j = 0; j < unaryCommandCount; ++j) + { + IFTPlatformException(unaryCommands.GetAt(j, out nUCode)); + currentCommands.Add(nUCode); + } + } + + if (commandType == CommandType.BinaryCommand) + { + IBinaryCommand spCommand = (IBinaryCommand)(command); + currentCommands.Add(spCommand.GetCommand()); + } + + if (commandType == CommandType.Parentheses) + { + IParenthesisCommand spCommand = (IParenthesisCommand)(command); + currentCommands.Add(spCommand.GetCommand()); + } + + if (commandType == CommandType.OperandCommand) + { + IOpndCommand spCommand = (IOpndCommand)(command); + CalculatorList opndCommands = spCommand.GetCommands(); + int opndCommandCount; + opndCommands.GetSize(out opndCommandCount); + bool fNeedIDCSign = spCommand.IsNegative(); + + int nOCode; + for (int j = 0; j < opndCommandCount; ++j) + { + IFTPlatformException(opndCommands.GetAt(j, out nOCode)); + currentCommands.Add(nOCode); + + if (fNeedIDCSign && nOCode != IDC_0) + { + currentCommands.Add((int)(CalculationManager.Command.CommandSIGN)); + fNeedIDCSign = false; + } + } + } + } + CalculatorList<(string, int)> savedTokens = new CalculatorList<(string, int)>(); + + int tokenCount; + IFTPlatformException(m_tokens.GetSize(out tokenCount)); + + for (int i = 0; i < tokenCount; ++i) + { + (string, int) currentToken; + IFTPlatformException(m_tokens.GetAt(i, out currentToken)); + savedTokens.Append(currentToken); + } + + m_standardCalculatorManager.Reset(false); + if (IsScientific) + { + m_standardCalculatorManager.SendCommand(Command.ModeScientific); + } + + if (IsFToEChecked) + { + m_standardCalculatorManager.SendCommand(Command.CommandFE); + } + + m_standardCalculatorManager.SendCommand(currentDegreeMode); + int currentCommandsSize = currentCommands.Count; + for (int i = 0; i < currentCommandsSize; i++) + { + m_standardCalculatorManager.SendCommand((CalculationManager.Command)(currentCommands[i])); + } + + if (fromHistory) // This is for the cases where the expression is loaded from history + { + // To maintain F-E state of the engine, as the last operand hasn't reached engine by now + m_standardCalculatorManager.SendCommand(Command.CommandFE); + m_standardCalculatorManager.SendCommand(Command.CommandFE); + } + + // After recalculation. If there is an error then + // IsInError should be set synchronously. + if (IsInError) + { + SetExpressionDisplay(savedTokens, savedCommands); + } + } + + CommandType GetSelectedTokenType(int tokenPosition) + { + (string, int) token; + IExpressionCommand tokenCommand; + IFTPlatformException(m_tokens.GetAt(tokenPosition, out token)); + + int tokenCommandIndex = token.Item2; + IFTPlatformException(m_commands.GetAt(tokenCommandIndex, out tokenCommand)); + + return tokenCommand.GetCommandType(); + } + + static Command[] opnd = { Command.Command0, Command.Command1, Command.Command2, Command.Command3, Command.Command4, Command.Command5, + Command.Command6, Command.Command7, Command.Command8, Command.Command9, Command.CommandPNT }; + + bool IsOpnd(int nOpCode) + { + for (uint i = 0; i < opnd.Length; i++) + { + if (nOpCode == (int)(opnd[i])) + { + return true; + } + } + return false; + } + + static Command[] unaryOp = { Command.CommandSQRT, Command.CommandFAC, Command.CommandSQR, Command.CommandLOG, + Command.CommandPOW10, Command.CommandPOWE, Command.CommandLN, Command.CommandREC, + Command.CommandSIGN, Command.CommandSINH, Command.CommandASINH, Command.CommandCOSH, + Command.CommandACOSH, Command.CommandTANH, Command.CommandATANH, Command.CommandCUB }; + + bool IsUnaryOp(int nOpCode) + { + for (uint i = 0; i < unaryOp.Length; i++) + { + if (nOpCode == (int)(unaryOp[i])) + { + return true; + } + } + + if (IsTrigOp(nOpCode)) + { + return true; + } + + return false; + } + + static Command[] trigOp = { + Command.CommandSIN, Command.CommandCOS, Command.CommandTAN, Command.CommandASIN, Command.CommandACOS, Command.CommandATAN + }; + bool IsTrigOp(int nOpCode) + { + + for (uint i = 0; i < trigOp.Length; i++) + { + if (nOpCode == (int)(trigOp[i])) + { + return true; + } + } + return false; + } + + static Command[] binOp = { Command.CommandADD, Command.CommandSUB, Command.CommandMUL, Command.CommandDIV, + Command.CommandEXP, Command.CommandROOT, Command.CommandMOD, Command.CommandPWR }; + + bool IsBinOp(int nOpCode) + { + for (uint i = 0; i < binOp.Length; i++) + { + if (nOpCode == (int)(binOp[i])) + { + return true; + } + } + return false; + } + + static Command[] recoverableCommands = { Command.CommandA, Command.CommandB, Command.CommandC, Command.CommandD, Command.CommandE, Command.CommandF }; + + bool IsRecoverableCommand(int nOpCode) + { + if (IsOpnd(nOpCode)) + { + return true; + } + + // Programmer mode, bit flipping + int minBinPos = (int)(Command.CommandBINEDITSTART); + int maxBinPos = (int)(Command.CommandBINEDITEND); + if (minBinPos <= nOpCode && nOpCode <= maxBinPos) + { + return true; + } + + + for (uint i = 0; i < recoverableCommands.Length; i++) + { + if (nOpCode == (int)(recoverableCommands[i])) + { + return true; + } + } + return false; + } + + int LengthWithoutPadding(string str) + { + int count = 0; + for (int i = 0; i < str.Length; i++) + { + if (str[i] != ' ') + { + count++; + } + } + return count; + } + + string AddPadding(string binaryString) + { + if (LocalizationSettings.GetInstance().GetEnglishValueFromLocalizedDigits(binaryString) == "0") + { + return binaryString; + } + int pad = 4 - LengthWithoutPadding(binaryString) % 4; + if (pad == 4) + { + pad = 0; + } + string padString = ""; + for (int i = 0; i < pad; i++) + { + padString += "0"; + } + return padString + binaryString; + } + + void UpdateProgrammerPanelDisplay() + { + string hexDisplayString = ""; + string decimalDisplayString = ""; + string octalDisplayString = ""; + string binaryDisplayString = ""; + + if (!IsInError) + { + // we want the precision to be set to maximum value so that the varconversions result as desired + int precision = 64; + if (m_standardCalculatorManager.GetResultForRadix(16, precision) == "") + { + hexDisplayString = DisplayValue; + decimalDisplayString = DisplayValue; + octalDisplayString = DisplayValue; + binaryDisplayString = DisplayValue; + } + else + { + hexDisplayString = m_standardCalculatorManager.GetResultForRadix(16, precision); + decimalDisplayString = m_standardCalculatorManager.GetResultForRadix(10, precision); + octalDisplayString = m_standardCalculatorManager.GetResultForRadix(8, precision); + binaryDisplayString = m_standardCalculatorManager.GetResultForRadix(2, precision); + } + } + var localizer = LocalizationSettings.GetInstance(); + binaryDisplayString = AddPadding(binaryDisplayString); + + localizer.LocalizeDisplayValue(ref hexDisplayString); + localizer.LocalizeDisplayValue(ref decimalDisplayString); + localizer.LocalizeDisplayValue(ref octalDisplayString); + localizer.LocalizeDisplayValue(ref binaryDisplayString); + + HexDisplayValue = Utils.LRO + hexDisplayString + Utils.PDF; + DecimalDisplayValue = Utils.LRO + decimalDisplayString + Utils.PDF; + OctalDisplayValue = Utils.LRO + octalDisplayString + Utils.PDF; + BinaryDisplayValue = Utils.LRO + binaryDisplayString + Utils.PDF; + HexDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedHexaDecimalAutomationFormat, GetNarratorStringReadRawNumbers(HexDisplayValue)); + DecDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedDecimalAutomationFormat, DecimalDisplayValue); + OctDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedOctalAutomationFormat, GetNarratorStringReadRawNumbers(OctalDisplayValue)); + BinDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedBinaryAutomationFormat, GetNarratorStringReadRawNumbers(BinaryDisplayValue)); + } + + public void SwitchAngleType(NumbersAndOperatorsEnum num) + { + OnButtonPressed(num); + } + + NumbersAndOperatorsEnum ConvertIntegerToNumbersAndOperatorsEnum(uint parameter) + { + NumbersAndOperatorsEnum angletype; + switch (parameter) + { + case 321: + angletype = NumbersAndOperatorsEnum.Degree; + break; + case 322: + angletype = NumbersAndOperatorsEnum.Radians; + break; + case 323: + angletype = NumbersAndOperatorsEnum.Grads; + break; + default: + angletype = NumbersAndOperatorsEnum.Degree; + break; + }; + return angletype; + } + + void UpdateOperand(int pos, String text) + { + (string, int) p; + m_tokens.GetAt(pos, out p); + + String englishString = LocalizationSettings.GetInstance().GetEnglishValueFromLocalizedDigits(text); + p.Item1 = englishString; + + int commandPos = p.Item2; + IExpressionCommand exprCmd; + m_commands.GetAt(commandPos, out exprCmd); + var operandCommand = (IOpndCommand)(exprCmd); + + if (operandCommand != null) + { + CalculatorList commands = new CalculatorList(); + int length = p.Item1.Length; + if (length > 0) + { + int num = 0; + for (int i = 0; i < length; ++i) + { + if (p.Item1[i] == '.') + { + num = (int)(Command.CommandPNT); + } + else if (p.Item1[i] == 'e') + { + num = (int)(Command.CommandEXP); + } + else if (p.Item1[i] == '-') + { + num = (int)(Command.CommandSIGN); + + if (i == 0) + { + IOpndCommand spOpndCommand = (IOpndCommand)(exprCmd); + if (!spOpndCommand.IsNegative()) + { + spOpndCommand.ToggleSign(); + } + continue; + } + } + else + { + num = (int)(p.Item1[i]) - ASCII_0; + num += IDC_0; + if (num == (int)(Command.CommandMPLUS)) + { + continue; + } + } + commands.Append(num); + } + } + else + { + commands.Append(0); + } + operandCommand.SetCommands(commands); + } + } + + void UpdatecommandsInRecordingMode() + { + List savedCommands = m_standardCalculatorManager.GetSavedCommands(); + CalculatorList commands = new CalculatorList(); + bool isDecimal = false; + bool isNegative = false; + bool isExpMode = false; + bool ePlusMode = false; + bool eMinusMode = false; + + int num = 0; + Command val; + for (int i = 0; i < savedCommands.Count; ++i) + { + val = (Command)(savedCommands[i]); + num = (int)(val); + if (val == Command.CommandSIGN) + { + isNegative = true; + continue; + } + else if ((val >= Command.Command0 && val <= Command.Command9)) + { + } + else if (val == Command.CommandPNT) + { + isDecimal = true; + } + else if (val == Command.CommandEXP) + { + isExpMode = true; + } + else if (isExpMode && !ePlusMode && (val == Command.CommandMPLUS)) + { + ePlusMode = true; + continue; + } + else if (isExpMode && !eMinusMode && (val == Command.CommandMMINUS)) + { + eMinusMode = true; + continue; + } + else + { + // Reset all vars + isDecimal = false; + isNegative = false; + isExpMode = false; + ePlusMode = false; + eMinusMode = false; + commands.Clear(); + continue; + } + commands.Append(num); + } + + int size = 0; + commands.GetSize(out size); + if (size > 0) + { + IOpndCommand sp = new COpndCommand(commands, isNegative, isDecimal, isExpMode); + m_commands.Append(sp); + } + Recalculate(); + } + + public void OnMaxDigitsReached() + { + String announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement( + MaxDigitsReachedFormat, m_localizedMaxDigitsReachedAutomationFormat, m_CalculationResultAutomationName); + + Announcement = CalculatorAnnouncement.GetMaxDigitsReachedAnnouncement(announcement); + } + + public void OnBinaryOperatorReceived() + { + Announcement = GetDisplayUpdatedNarratorAnnouncement(); + } + + NarratorAnnouncement GetDisplayUpdatedNarratorAnnouncement() + { + String announcement; + if (m_feedbackForButtonPress == null || string.IsNullOrEmpty(m_feedbackForButtonPress)) + { + announcement = m_CalculationResultAutomationName; + } + else + { + announcement = LocalizationStringUtil.GetLocalizedNarratorAnnouncement( + ButtonPressFeedbackFormat, + m_localizedButtonPressFeedbackAutomationFormat, + m_CalculationResultAutomationName, + m_feedbackForButtonPress); + } + + // Make sure we don't accidentally repeat an announcement. + m_feedbackForButtonPress = null; + + return CalculatorAnnouncement.GetDisplayUpdatedAnnouncement(announcement); + } + + private void IFTPlatformException(bool result) { /* hresult validation is not used in C# */} + } +} \ No newline at end of file diff --git a/src/Calculator.Shared/ViewModels/UnitConverterViewModel.cs b/src/Calculator.Shared/ViewModels/UnitConverterViewModel.cs new file mode 100644 index 00000000..23fd72fc --- /dev/null +++ b/src/Calculator.Shared/ViewModels/UnitConverterViewModel.cs @@ -0,0 +1,10 @@ +//using System; +//using System.Collections.Generic; +//using System.Text; + +//namespace WindowsCalculator.Shared.ViewModels +//{ +// class UnitConverterViewModel +// { +// } +//} diff --git a/src/Calculator.Shared/ViewModels/ViewState.cs b/src/Calculator.Shared/ViewModels/ViewState.cs new file mode 100644 index 00000000..b181cd8d --- /dev/null +++ b/src/Calculator.Shared/ViewModels/ViewState.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CalculatorApp +{ + public class ViewState + { + public const string Snap = "Snap"; + public const string DockedView = "DockedView"; + + public bool IsValidViewState(string viewState) => viewState.Equals(ViewState.Snap) || viewState.Equals(ViewState.DockedView); + } +} diff --git a/src/Calculator.Shared/Views/AboutFlyout.xaml b/src/Calculator.Shared/Views/AboutFlyout.xaml new file mode 100644 index 00000000..9032dd6c --- /dev/null +++ b/src/Calculator.Shared/Views/AboutFlyout.xaml @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/Calculator.Shared/Views/AboutFlyout.xaml.cs b/src/Calculator.Shared/Views/AboutFlyout.xaml.cs new file mode 100644 index 00000000..f0eac07c --- /dev/null +++ b/src/Calculator.Shared/Views/AboutFlyout.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 + +namespace CalculatorApp +{ + public sealed partial class AboutFlyout : UserControl + { + public AboutFlyout() + { + this.InitializeComponent(); + } + } +} diff --git a/src/Calculator.Shared/Views/Calculator.xaml b/src/Calculator.Shared/Views/Calculator.xaml new file mode 100644 index 00000000..d3a5d0b3 --- /dev/null +++ b/src/Calculator.Shared/Views/Calculator.xaml @@ -0,0 +1,1580 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +