Added initial sources

Base commit ID: 9f01c8168b
This commit is contained in:
Jérôme Laban 2019-05-14 14:20:35 -04:00
commit 20668f8f03
782 changed files with 24953 additions and 47110 deletions

View file

@ -0,0 +1,126 @@
#include "pch.h"
#include "CCalcManager.h"
#include "CalculatorManager.h"
#include "CalculatorResource.h"
#include <codecvt>
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<std::codecvt_utf8<wchar_t>> 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<CalculatorVector<std::pair<std::wstring, int>>> const& /*tokens*/,
std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> 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<std::wstring>& memorizedNumbers) override
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> 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<std::codecvt_utf8<wchar_t>> 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<CalculatorManager*>(manager))->SendCommand((Command)command);
}

View file

@ -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);
}

View file

@ -2,7 +2,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
#include <sstream> #include <sstream>
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "Header Files/CalcUtils.h" #include "headers/CalcUtils.h"
bool IsOpInRange(OpCode op, uint32_t x, uint32_t y) bool IsOpInRange(OpCode op, uint32_t x, uint32_t y)
{ {

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "Command.h" #include "Command.h"
#include "CalculatorVector.h" #include "CalculatorVector.h"
#include "ExpressionCommand.h" #include "ExpressionCommand.h"

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
#include <algorithm> #include <algorithm>
#include "Header Files/Number.h" #include "headers/Number.h"
using namespace std; using namespace std;

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
#include <intsafe.h> //#include <intsafe.h>
#include "Header Files/Rational.h" #include "headers/Rational.h"
using namespace std; using namespace std;

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "Header Files/RationalMath.h" #include "headers/RationalMath.h"
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;

View file

@ -2,7 +2,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
#include <cassert> #include <cassert>
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "CalculatorResource.h" #include "CalculatorResource.h"
using namespace std; using namespace std;

View file

@ -14,8 +14,8 @@
\****************************************************************************/ \****************************************************************************/
#include <string> #include <string>
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "Header Files/CalcUtils.h" #include "headers/CalcUtils.h"
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;

View file

@ -15,7 +15,7 @@
#include <sstream> #include <sstream>
#include <regex> #include <regex>
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;
@ -48,7 +48,6 @@ typedef struct
bool bUseSep; bool bUseSep;
} LASTDISP; } 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 // 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) CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational const& rat)
@ -77,6 +76,8 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con
void CCalcEngine::DisplayNum(void) void CCalcEngine::DisplayNum(void)
{ {
static LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
// //
// Only change the display if // Only change the display if
// we are in record mode -OR- // we are in record mode -OR-

View file

@ -16,7 +16,7 @@
/*** ***/ /*** ***/
/*** ***/ /*** ***/
/**************************************************************************/ /**************************************************************************/
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
using namespace CalcEngine; using namespace CalcEngine;
using namespace CalcEngine::RationalMath; using namespace CalcEngine::RationalMath;

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
using namespace CalcEngine; using namespace CalcEngine;
using namespace CalcEngine::RationalMath; using namespace CalcEngine::RationalMath;

View file

@ -41,7 +41,7 @@
<RootNamespace>CalcManager</RootNamespace> <RootNamespace>CalcManager</RootNamespace>
<DisableAppLocalVCLibs>false</DisableAppLocalVCLibs> <DisableAppLocalVCLibs>false</DisableAppLocalVCLibs>
<DefaultLanguage>en-US</DefaultLanguage> <DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion> <MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication> <AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType> <ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision> <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
@ -56,46 +56,46 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -158,6 +158,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles> <ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_UNICODE;UNICODE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -222,7 +223,7 @@
<CompileAsWinRT>false</CompileAsWinRT> <CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/Zm250 /await /std:c++17 /permissive- /Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_UNICODE;UNICODE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
@ -290,21 +291,23 @@
<ClInclude Include="CalculatorManager.h" /> <ClInclude Include="CalculatorManager.h" />
<ClInclude Include="CalculatorResource.h" /> <ClInclude Include="CalculatorResource.h" />
<ClInclude Include="CalculatorVector.h" /> <ClInclude Include="CalculatorVector.h" />
<ClInclude Include="CCalcManager.h" />
<ClInclude Include="Command.h" /> <ClInclude Include="Command.h" />
<ClInclude Include="compat.h" />
<ClInclude Include="ExpressionCommand.h" /> <ClInclude Include="ExpressionCommand.h" />
<ClInclude Include="ExpressionCommandInterface.h" /> <ClInclude Include="ExpressionCommandInterface.h" />
<ClInclude Include="Header Files\CalcEngine.h" /> <ClInclude Include="headers\CalcEngine.h" />
<ClInclude Include="Header Files\CalcUtils.h" /> <ClInclude Include="headers\CalcInput.h" />
<ClInclude Include="Header Files\CCommand.h" /> <ClInclude Include="headers\CalcUtils.h" />
<ClInclude Include="Header Files\EngineStrings.h" /> <ClInclude Include="headers\CCommand.h" />
<ClInclude Include="Header Files\History.h" /> <ClInclude Include="headers\EngineStrings.h" />
<ClInclude Include="Header Files\ICalcDisplay.h" /> <ClInclude Include="headers\History.h" />
<ClInclude Include="Header Files\CalcInput.h" /> <ClInclude Include="headers\ICalcDisplay.h" />
<ClInclude Include="Header Files\IHistoryDisplay.h" /> <ClInclude Include="headers\IHistoryDisplay.h" />
<ClInclude Include="Header Files\Number.h" /> <ClInclude Include="headers\Number.h" />
<ClInclude Include="Header Files\RadixType.h" /> <ClInclude Include="headers\RadixType.h" />
<ClInclude Include="Header Files\Rational.h" /> <ClInclude Include="headers\Rational.h" />
<ClInclude Include="Header Files\RationalMath.h" /> <ClInclude Include="headers\RationalMath.h" />
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
<ClInclude Include="Ratpack\CalcErr.h" /> <ClInclude Include="Ratpack\CalcErr.h" />
<ClInclude Include="Ratpack\ratconst.h" /> <ClInclude Include="Ratpack\ratconst.h" />
@ -314,6 +317,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="CalculatorHistory.cpp" /> <ClCompile Include="CalculatorHistory.cpp" />
<ClCompile Include="CalculatorManager.cpp" /> <ClCompile Include="CalculatorManager.cpp" />
<ClCompile Include="CCalcManager.cpp" />
<ClCompile Include="CEngine\calc.cpp" /> <ClCompile Include="CEngine\calc.cpp" />
<ClCompile Include="CEngine\CalcUtils.cpp" /> <ClCompile Include="CEngine\CalcUtils.cpp" />
<ClCompile Include="CEngine\History.cpp" /> <ClCompile Include="CEngine\History.cpp" />

View file

@ -7,7 +7,7 @@
<Filter Include="RatPack"> <Filter Include="RatPack">
<UniqueIdentifier>{a1bae6f0-0a01-447d-9a3a-5c65bcd384e6}</UniqueIdentifier> <UniqueIdentifier>{a1bae6f0-0a01-447d-9a3a-5c65bcd384e6}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Header Files"> <Filter Include="headers">
<UniqueIdentifier>{5149465e-c5c9-48a2-b676-f11380b733a0}</UniqueIdentifier> <UniqueIdentifier>{5149465e-c5c9-48a2-b676-f11380b733a0}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
@ -89,27 +89,13 @@
<ClCompile Include="CEngine\RationalMath.cpp"> <ClCompile Include="CEngine\RationalMath.cpp">
<Filter>CEngine</Filter> <Filter>CEngine</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="CCalcManager.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Command.h" /> <ClInclude Include="Command.h" />
<ClInclude Include="ExpressionCommand.h" /> <ClInclude Include="ExpressionCommand.h" />
<ClInclude Include="ExpressionCommandInterface.h" /> <ClInclude Include="ExpressionCommandInterface.h" />
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
<ClInclude Include="Header Files\History.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcEngine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CCommand.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\EngineStrings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Ratpack\CalcErr.h"> <ClInclude Include="Ratpack\CalcErr.h">
<Filter>RatPack</Filter> <Filter>RatPack</Filter>
</ClInclude> </ClInclude>
@ -120,45 +106,49 @@
<Filter>RatPack</Filter> <Filter>RatPack</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="CalculatorVector.h" /> <ClInclude Include="CalculatorVector.h" />
<ClInclude Include="Header Files\CalcEngine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CalcUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\CCommand.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\EngineStrings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Header Files\History.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UnitConverter.h" /> <ClInclude Include="UnitConverter.h" />
<ClInclude Include="CalculatorHistory.h" /> <ClInclude Include="CalculatorHistory.h" />
<ClInclude Include="CalculatorManager.h" /> <ClInclude Include="CalculatorManager.h" />
<ClInclude Include="CalculatorResource.h" /> <ClInclude Include="CalculatorResource.h" />
<ClInclude Include="Header Files\ICalcDisplay.h"> <ClInclude Include="headers\CalcEngine.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Header Files\CalcInput.h"> <ClInclude Include="headers\CalcInput.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Header Files\IHistoryDisplay.h"> <ClInclude Include="headers\CalcUtils.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Header Files\Number.h"> <ClInclude Include="headers\CCommand.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Header Files\Rational.h"> <ClInclude Include="headers\EngineStrings.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Header Files\RadixType.h"> <ClInclude Include="headers\History.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Header Files\RationalMath.h"> <ClInclude Include="headers\ICalcDisplay.h">
<Filter>Header Files</Filter> <Filter>headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="headers\IHistoryDisplay.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="headers\Number.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="headers\RadixType.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="headers\Rational.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="headers\RationalMath.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="compat.h">
<Filter>headers</Filter>
</ClInclude>
<ClInclude Include="CCalcManager.h" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "ExpressionCommandInterface.h" #include "ExpressionCommandInterface.h"
#include "Header Files/IHistoryDisplay.h" #include "headers/IHistoryDisplay.h"
namespace CalculationManager namespace CalculationManager
{ {

View file

@ -2,7 +2,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
#include <climits> // for UCHAR_MAX #include <climits> // for UCHAR_MAX
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "CalculatorManager.h" #include "CalculatorManager.h"
#include "CalculatorResource.h" #include "CalculatorResource.h"

View file

@ -4,9 +4,9 @@
#pragma once #pragma once
#include "CalculatorHistory.h" #include "CalculatorHistory.h"
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "Header Files/Rational.h" #include "headers/Rational.h"
#include "Header Files/ICalcDisplay.h" #include "headers/ICalcDisplay.h"
namespace CalculationManager namespace CalculationManager
{ {

View file

@ -5,10 +5,17 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <winerror.h> #include <array>
#include <unordered_map>
#include "Ratpack/CalcErr.h" #include "Ratpack/CalcErr.h"
#include <stdexcept> // for std::out_of_range #include <stdexcept> // for std::out_of_range
#if !defined(__WEBASSEMBLY__)
#include <winerror.h>
#include <sal.h> // for SAL #include <sal.h> // for SAL
#endif
#include "compat.h"
template <typename TType> template <typename TType>
class CalculatorVector class CalculatorVector

View file

@ -2,7 +2,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
#include <string> #include <string>
#include "Header Files/CCommand.h" #include "headers/CCommand.h"
#include "CalculatorVector.h" #include "CalculatorVector.h"
#include "ExpressionCommand.h" #include "ExpressionCommand.h"

View file

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "ExpressionCommandInterface.h" #include "ExpressionCommandInterface.h"
#include "Header Files/CalcEngine.h" #include "headers/CalcEngine.h"
#include "Header Files/Rational.h" #include "headers/Rational.h"
class CParentheses final : public IParenthesisCommand class CParentheses final : public IParenthesisCommand
{ {

View file

@ -18,10 +18,11 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <algorithm> #include <algorithm>
#include <winerror.h> // #include <winerror.h>
#include <sstream> #include <sstream>
#include <cstring> // for memmove, memcpy #include <cstring> // for memmove, memcpy
#include "ratpak.h" #include "ratpak.h"
#include "compat.h"
using namespace std; 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))) #define Calc_UInt32x32To64(a, b) ((uint64_t)((uint32_t)(a)) * (uint64_t)((uint32_t)(b)))
#endif #endif
#elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) #elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__EMSCRIPTEN__)
#ifndef Calc_UInt32x32To64 #ifndef Calc_UInt32x32To64
#define Calc_UInt32x32To64(a, b) (uint64_t)((uint64_t)(uint32_t)(a) * (uint32_t)(b)) #define Calc_UInt32x32To64(a, b) (uint64_t)((uint64_t)(uint32_t)(a) * (uint32_t)(b))

File diff suppressed because it is too large Load diff

View file

@ -21,7 +21,8 @@
#include <string> #include <string>
#include "CalcErr.h" #include "CalcErr.h"
#include <cstring> // for memmove #include <cstring> // for memmove
#include <sal.h> // for SAL // #include <sal.h> // for SAL
#include "compat.h"
static constexpr uint32_t BASEXPWR = 31L; // Internal log2(BASEX) static constexpr uint32_t BASEXPWR = 31L; // Internal log2(BASEX)
static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculations, hope to raise static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculations, hope to raise

30
src/CalcManager/compat.h Normal file
View file

@ -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

View file

@ -17,6 +17,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <array>
inline constexpr auto IDS_ERRORS_FIRST = 99; inline constexpr auto IDS_ERRORS_FIRST = 99;

View file

@ -7,6 +7,7 @@
#include "ICalcDisplay.h" #include "ICalcDisplay.h"
#include "IHistoryDisplay.h" #include "IHistoryDisplay.h"
#include "Rational.h" #include "Rational.h"
#include "compat.h"
// maximum depth you can get by precedence. It is just an array's size limit. // maximum depth you can get by precedence. It is just an array's size limit.
static constexpr size_t MAXPRECDEPTH = 25; static constexpr size_t MAXPRECDEPTH = 25;

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "Number.h" #include "Number.h"
#include "compat.h"
namespace CalcEngine namespace CalcEngine
{ {

View file

@ -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<NavCategoryGroup ^> ^ 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<UnitConverterDataLoader>(ref new GeographicRegion());
auto currencyDataLoader = make_shared<CurrencyDataLoader>(make_unique<CurrencyHttpClient>());
m_ConverterViewModel = ref new UnitConverterViewModel(make_shared<UnitConversionManager::UnitConverter>(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();
}

View file

@ -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<CalculatorApp::Common::NavCategoryGroup^>^ Categories
{
Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ get()
{
return m_categories;
}
void set(Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ 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<CalculatorApp::Common::NavCategoryGroup ^> ^ m_categories;
};
}
}

View file

@ -1,425 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{90e9761d-9262-4773-942d-caeae75d7140}</ProjectGuid>
<Keyword>StaticLibrary</Keyword>
<RootNamespace>CalcViewModel</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(IsStoreBuild)' == 'True'">
<ClCompile>
<AdditionalOptions>/DSEND_TELEMETRY %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ApplicationViewModel.h" />
<ClInclude Include="Common\AlwaysSelectedCollectionView.h" />
<ClInclude Include="Common\AppResourceProvider.h" />
<ClInclude Include="Common\Automation\INarratorAnnouncementHost.h" />
<ClInclude Include="Common\Automation\LiveRegionHost.h" />
<ClInclude Include="Common\Automation\NarratorAnnouncement.h" />
<ClInclude Include="Common\Automation\NarratorAnnouncementHostFactory.h" />
<ClInclude Include="Common\Automation\NarratorNotifier.h" />
<ClInclude Include="Common\Automation\NotificationHost.h" />
<ClInclude Include="Common\BindableBase.h" />
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h" />
<ClInclude Include="Common\CalculatorButtonUser.h" />
<ClInclude Include="Common\CalculatorDisplay.h" />
<ClInclude Include="Common\ConversionResultTaskHelper.h" />
<ClInclude Include="Common\CopyPasteManager.h" />
<ClInclude Include="Common\DateCalculator.h" />
<ClInclude Include="Common\DelegateCommand.h" />
<ClInclude Include="Common\DisplayExpressionToken.h" />
<ClInclude Include="Common\EngineResourceProvider.h" />
<ClInclude Include="Common\ExpressionCommandDeserializer.h" />
<ClInclude Include="Common\ExpressionCommandSerializer.h" />
<ClInclude Include="Common\KeyboardShortcutManager.h" />
<ClInclude Include="Common\LocalizationService.h" />
<ClInclude Include="Common\LocalizationSettings.h" />
<ClInclude Include="Common\LocalizationStringUtil.h" />
<ClInclude Include="Common\MyVirtualKey.h" />
<ClInclude Include="Common\NavCategory.h" />
<ClInclude Include="Common\NetworkManager.h" />
<ClInclude Include="Common\TraceActivity.h" />
<ClInclude Include="Common\TraceLogger.h" />
<ClInclude Include="Common\Utils.h" />
<ClInclude Include="Common\ValidatingConverters.h" />
<ClInclude Include="DataLoaders\CurrencyDataLoader.h" />
<ClInclude Include="DataLoaders\CurrencyHttpClient.h" />
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h" />
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h" />
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h" />
<ClInclude Include="DateCalculatorViewModel.h" />
<ClInclude Include="HistoryItemViewModel.h" />
<ClInclude Include="HistoryViewModel.h" />
<ClInclude Include="MemoryItemViewModel.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="StandardCalculatorViewModel.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="UnitConverterViewModel.h" />
<ClInclude Include="ViewState.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ApplicationViewModel.cpp" />
<ClCompile Include="Common\AppResourceProvider.cpp" />
<ClCompile Include="Common\Automation\LiveRegionHost.cpp" />
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp" />
<ClCompile Include="Common\Automation\NarratorAnnouncementHostFactory.cpp" />
<ClCompile Include="Common\Automation\NarratorNotifier.cpp" />
<ClCompile Include="Common\Automation\NotificationHost.cpp" />
<ClCompile Include="Common\BindableBase.cpp" />
<ClCompile Include="Common\CalculatorButtonPressedEventArgs.cpp" />
<ClCompile Include="Common\CalculatorDisplay.cpp" />
<ClCompile Include="Common\ConversionResultTaskHelper.cpp" />
<ClCompile Include="Common\CopyPasteManager.cpp" />
<ClCompile Include="Common\DateCalculator.cpp" />
<ClCompile Include="Common\EngineResourceProvider.cpp" />
<ClCompile Include="Common\ExpressionCommandDeserializer.cpp" />
<ClCompile Include="Common\ExpressionCommandSerializer.cpp" />
<ClCompile Include="Common\KeyboardShortcutManager.cpp" />
<ClCompile Include="Common\LocalizationService.cpp" />
<ClCompile Include="Common\NavCategory.cpp" />
<ClCompile Include="Common\NetworkManager.cpp" />
<ClCompile Include="Common\TraceLogger.cpp" />
<ClCompile Include="Common\Utils.cpp" />
<ClCompile Include="DataLoaders\CurrencyDataLoader.cpp" />
<ClCompile Include="DataLoaders\CurrencyHttpClient.cpp" />
<ClCompile Include="DataLoaders\UnitConverterDataLoader.cpp" />
<ClCompile Include="DateCalculatorViewModel.cpp" />
<ClCompile Include="HistoryItemViewModel.cpp" />
<ClCompile Include="HistoryViewModel.cpp" />
<ClCompile Include="MemoryItemViewModel.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="StandardCalculatorViewModel.cpp" />
<ClCompile Include="UnitConverterViewModel.cpp" />
<ClCompile Include="ViewState.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
<Project>{311e866d-8b93-4609-a691-265941fee101}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="DataLoaders\DefaultFromToCurrency.json" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.UI.Xaml.2.0.181018003.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\packages\Microsoft.UI.Xaml.2.0.181018003.1\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.UI.Xaml.2.0.181018003.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.UI.Xaml.2.0.181018003.1\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
</Project>

View file

@ -1,223 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Common">
<UniqueIdentifier>{1daab7c4-63f6-4266-a259-f34acad66d09}</UniqueIdentifier>
</Filter>
<Filter Include="Common\Automation">
<UniqueIdentifier>{8d4edf06-c312-4312-978a-b6c2beb8295a}</UniqueIdentifier>
</Filter>
<Filter Include="DataLoaders">
<UniqueIdentifier>{0184f727-b8aa-4af8-a699-63f1b56e7853}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="ApplicationViewModel.cpp" />
<ClCompile Include="DateCalculatorViewModel.cpp" />
<ClCompile Include="HistoryItemViewModel.cpp" />
<ClCompile Include="HistoryViewModel.cpp" />
<ClCompile Include="MemoryItemViewModel.cpp" />
<ClCompile Include="StandardCalculatorViewModel.cpp" />
<ClCompile Include="UnitConverterViewModel.cpp" />
<ClCompile Include="ViewState.cpp" />
<ClCompile Include="Common\AppResourceProvider.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\BindableBase.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\CalculatorButtonPressedEventArgs.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\CalculatorDisplay.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\ConversionResultTaskHelper.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\CopyPasteManager.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\DateCalculator.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\EngineResourceProvider.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\ExpressionCommandDeserializer.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\ExpressionCommandSerializer.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\KeyboardShortcutManager.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\LocalizationService.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\NavCategory.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\NetworkManager.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\TraceLogger.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\Utils.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\LiveRegionHost.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NarratorAnnouncementHostFactory.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NarratorNotifier.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NotificationHost.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="DataLoaders\CurrencyDataLoader.cpp">
<Filter>DataLoaders</Filter>
</ClCompile>
<ClCompile Include="DataLoaders\CurrencyHttpClient.cpp">
<Filter>DataLoaders</Filter>
</ClCompile>
<ClCompile Include="DataLoaders\UnitConverterDataLoader.cpp">
<Filter>DataLoaders</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="ApplicationViewModel.h" />
<ClInclude Include="DateCalculatorViewModel.h" />
<ClInclude Include="HistoryItemViewModel.h" />
<ClInclude Include="HistoryViewModel.h" />
<ClInclude Include="MemoryItemViewModel.h" />
<ClInclude Include="StandardCalculatorViewModel.h" />
<ClInclude Include="UnitConverterViewModel.h" />
<ClInclude Include="ViewState.h" />
<ClInclude Include="Common\AlwaysSelectedCollectionView.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\AppResourceProvider.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\BindableBase.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\CalculatorButtonUser.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\CalculatorDisplay.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\ConversionResultTaskHelper.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\CopyPasteManager.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\DateCalculator.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\DelegateCommand.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\DisplayExpressionToken.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\EngineResourceProvider.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\ExpressionCommandDeserializer.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\ExpressionCommandSerializer.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\KeyboardShortcutManager.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\LocalizationService.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\LocalizationSettings.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\LocalizationStringUtil.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\MyVirtualKey.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\NavCategory.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\NetworkManager.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\TraceLogger.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\Utils.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\ValidatingConverters.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\INarratorAnnouncementHost.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\LiveRegionHost.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NarratorAnnouncement.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NarratorAnnouncementHostFactory.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NarratorNotifier.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NotificationHost.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\CurrencyDataLoader.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\CurrencyHttpClient.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="Common\TraceActivity.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="DataLoaders\DefaultFromToCurrency.json">
<Filter>DataLoaders</Filter>
</None>
<None Include="packages.config" />
</ItemGroup>
</Project>

View file

@ -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<Windows::UI::Xaml::Interop::IBindableObservableVector ^>(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<Platform::Object ^> ^ CollectionGroups {
virtual Windows::Foundation::Collections::IObservableVector<
Platform::Object ^> ^ get() = Windows::UI::Xaml::Data::ICollectionView::CollectionGroups::get
{
return ref new Platform::Collections::Vector<Platform::Object ^>();
}
} 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<int>(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<int>(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<int>(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<int>(m_source->Size);
}
}
property bool IsCurrentBeforeFirst
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentBeforeFirst::get
{
return m_currentPosition < 0;
}
}
event WF::EventHandler<Platform::Object^>^ CurrentChanged
{
virtual WF::EventRegistrationToken add(WF::EventHandler<Platform::Object^>^ 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<Object^>
// Not implemented methods
virtual void Append(Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::Append
{
throw ref new Platform::NotImplementedException();
}
virtual void Clear() = Windows::Foundation::Collections::IVector<Platform::Object ^>::Clear
{
throw ref new Platform::NotImplementedException();
}
virtual unsigned int GetMany(
unsigned int /*startIndex*/,
Platform::WriteOnlyArray<Platform::Object ^> ^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::GetMany
{
throw ref new Platform::NotImplementedException();
}
virtual Windows::Foundation::Collections::IVectorView<Platform::Object ^> ^ 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<Platform::Object ^>::InsertAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAt(unsigned int /*index*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::RemoveAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAtEnd() = Windows::Foundation::Collections::IVector<Platform::Object ^>::RemoveAtEnd
{
throw ref new Platform::NotImplementedException();
}
virtual void
ReplaceAll(const Platform::Array<Platform::Object ^> ^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::ReplaceAll
{
throw ref new Platform::NotImplementedException();
}
virtual void SetAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::SetAt
{
throw ref new Platform::NotImplementedException();
}
// Implemented methods
virtual Platform::Object ^ GetAt(unsigned int index) = Windows::Foundation::Collections::IVector<Platform::Object ^>::GetAt
{
return m_source->GetAt(index);
}
virtual bool IndexOf(Platform::Object ^ item, unsigned int* index) = Windows::Foundation::Collections::IVector<Platform::Object ^>::IndexOf
{
return m_source->IndexOf(item, index);
}
property unsigned int Size
{
virtual unsigned int get() = Windows::Foundation::Collections::IVector<Platform::Object ^>::Size::get
{
return m_source->Size;
}
}
// IObservableVector<Object^>
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ VectorChanged
{
virtual WF::EventRegistrationToken add(Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ handler) = Windows::Foundation::Collections::IObservableVector<Platform::Object^>::VectorChanged::add
{
return m_vectorChanged += handler;
}
virtual void remove(WF::EventRegistrationToken token) = Windows::Foundation::Collections::IObservableVector<Platform::Object^>::VectorChanged::remove
{
m_vectorChanged -= token;
}
}
// IIterable<Object^>
// Not implemented
virtual Windows::Foundation::Collections::IIterator<Platform::Object^>^ First() = Windows::Foundation::Collections::IIterable<Platform::Object^>::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<Windows::Foundation::Collections::IVectorChangedEventArgs ^>(e);
m_vectorChanged(this, args);
}
Windows::UI::Xaml::Interop::IBindableVector ^ m_source;
int m_currentPosition;
event WF::EventHandler<Platform::Object ^> ^ m_currentChanged;
event Windows::UI::Xaml::Data::CurrentChangingEventHandler ^ m_currentChanging;
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object ^> ^ 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<Windows::UI::Xaml::Interop::IBindableVector ^>(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;
}
};
}
}

View file

@ -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);
}

View file

@ -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;
};
}

View file

@ -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);
};
}

View file

@ -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);
}
}

View file

@ -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;
};
}

View file

@ -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);
}

View file

@ -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);
};
}

View file

@ -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<INarratorAnnouncementHost ^> 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();
}

View file

@ -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<INarratorAnnouncementHost ^> s_hosts;
};
}

View file

@ -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<NarratorNotifier ^>(dependencyObject);
if (instance != nullptr)
{
instance->Announce(safe_cast<NarratorAnnouncement ^>(e->NewValue));
}
}

View file

@ -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<NarratorAnnouncement ^>(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;
};
}

View file

@ -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;
}

View file

@ -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;
};
}

View file

@ -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;
/// <summary>
/// Notifies listeners that a property value has changed.
/// </summary>
/// <param name="propertyName">Name of the property used to notify listeners.</param>
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();
}

View file

@ -1,38 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Common
{
/// <summary>
/// Implementation of <see cref="INotifyPropertyChanged"/> to simplify models.
/// </summary>
[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);
};
}
}

View file

@ -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<CalculatorButtonPressedEventArgs ^>(commandParameter);
if (eventArgs != nullptr)
{
return eventArgs->Operation;
}
else
{
return safe_cast<NumbersAndOperatorsEnum>(commandParameter);
}
}
String ^ CalculatorButtonPressedEventArgs::GetAuditoryFeedbackFromCommandParameter(_In_ Object ^ commandParameter)
{
auto eventArgs = dynamic_cast<CalculatorButtonPressedEventArgs ^>(commandParameter);
if (eventArgs != nullptr)
{
return eventArgs->AuditoryFeedback;
}
else
{
return nullptr;
}
}

View file

@ -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);
};
}
}

View file

@ -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,
};
}

View file

@ -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<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetPrimaryDisplay(displayStringValue, isError);
}
}
}
void CalculatorDisplay::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetParenthesisCount(parenthesisCount);
}
}
}
void CalculatorDisplay::OnNoRightParenAdded()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnNoRightParenAdded();
}
}
}
void CalculatorDisplay::SetIsInError(bool isError)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->IsInError = isError;
}
}
}
void CalculatorDisplay::SetExpressionDisplay(
_Inout_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const& commands)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetExpressionDisplay(tokens, commands);
}
}
}
void CalculatorDisplay::SetMemorizedNumbers(_In_ const vector<std::wstring>& newMemorizedNumbers)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetMemorizedNumbers(newMemorizedNumbers);
}
}
}
void CalculatorDisplay::OnHistoryItemAdded(_In_ unsigned int addedItemIndex)
{
if (m_historyCallbackReference != nullptr)
{
if (auto historyVM = m_historyCallbackReference.Resolve<ViewModel::HistoryViewModel>())
{
historyVM->OnHistoryItemAdded(addedItemIndex);
}
}
}
void CalculatorDisplay::MaxDigitsReached()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnMaxDigitsReached();
}
}
}
void CalculatorDisplay::BinaryOperatorReceived()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnBinaryOperatorReceived();
}
}
}
void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnMemoryItemChanged(indexOfMemory);
}
}
}

View file

@ -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<CalculatorVector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const& commands) override;
void SetMemorizedNumbers(_In_ const std::vector<std::wstring>& 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;
};
}

View file

@ -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<void()> 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<void> ConversionResultTaskHelper::CompleteAfter(unsigned int timeout)
{
co_await winrt::resume_after(winrt::Windows::Foundation::TimeSpan{ std::chrono::duration<uint32_t, std::milli>(timeout) });
};
#pragma optimize("", on)

View file

@ -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<void()> functionToRun);
~ConversionResultTaskHelper();
private:
concurrency::task<void> CompleteAfter(unsigned int timeout);
unsigned int m_delay;
concurrency::cancellation_token_source m_cts;
const std::function<void()> m_storedFunction;
};
}
}

View file

@ -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<wregex, 1> standardModePatterns = { wregex(c_wspc + c_signedDecFloat + c_wspc) };
static const array<wregex, 2> 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<array<wregex, 5>, 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<wregex, 1> 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<String ^> 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<wstring> 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<wstring> CopyPasteManager::ExtractOperands(const wstring& pasteExpression, ViewMode mode, int programmerNumberBase, int bitLengthType)
{
vector<wstring> 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<wstring> operands, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType)
{
if (operands.empty())
{
return false;
}
vector<wregex> 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<size_t, uint64_t> 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<size_t>(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<int>(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<wstring> prefixes{};
vector<wstring> 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<wstring, 5> 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);
}

View file

@ -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<Platform::String ^> 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<std::wstring>
ExtractOperands(const std::wstring& pasteExpression, CalculatorApp::Common::ViewMode mode, int programmerNumberBase = -1, int bitLengthType = -1);
static bool ExpressionRegExMatch(
std::vector<std::wstring> operands,
CalculatorApp::Common::ViewMode mode,
CalculatorApp::Common::CategoryGroupType modeType,
int programmerNumberBase = -1,
int bitLengthType = -1);
static std::pair<size_t, uint64_t> 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;
};
}

View file

@ -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<int>(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<DateUnit>(1 << unitIndex);
if (static_cast<int>(outputFormat & dateUnit))
{
bool isEndDateHit = false;
differenceInDates[unitIndex] = (daysDiff / daysIn[unitIndex]);
if (differenceInDates[unitIndex] != 0)
{
try
{
pivotDate = AdjustCalendarDate(pivotDate, dateUnit, static_cast<int>(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<int>(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<int>(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<int>(ticksDifference / static_cast<long long>(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<UINT>(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();
}

View file

@ -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);
};
}
}
}

View file

@ -1,68 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Common
{
template <typename TTarget>
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<TTarget>();
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<Platform::Object^>^ CanExecuteChangedImpl
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::Foundation::EventHandler<Platform::Object^>^ 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<Platform::Object^>^ m_canExecuteChanged;
CommandHandlerFunc m_function;
Platform::WeakReference m_weakTarget;
};
template <typename TTarget, typename TFuncPtr>
DelegateCommand<TTarget> ^ MakeDelegate(TTarget ^ target, TFuncPtr&& function) {
return ref new DelegateCommand<TTarget>(target, std::forward<TFuncPtr>(function));
}
}
}

View file

@ -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;
};
}

View file

@ -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();
}
}

View file

@ -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;
};
}

View file

@ -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<IExpressionCommand> CommandDeserializer::Deserialize(_In_ CalculationManager::CommandType cmdType)
{
switch (cmdType)
{
case CalculationManager::CommandType::OperandCommand:
return std::make_shared<COpndCommand>(DeserializeOperand());
break;
case CalculationManager::CommandType::Parentheses:
return std::make_shared<CParentheses>(DeserializeParentheses());
break;
case CalculationManager::CommandType::UnaryCommand:
return std::make_shared<CUnaryCommand>(DeserializeUnary());
break;
case CalculationManager::CommandType::BinaryCommand:
return std::make_shared<CBinaryCommand>(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<CalculatorVector<int>> cmdVector = std::make_shared<CalculatorVector<int>>();
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<CalculatorVector<int>> cmdVector = std::make_shared<CalculatorVector<int>>();
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);
}

View file

@ -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<IExpressionCommand> Deserialize(_In_ CalculationManager::CommandType cmdType);
private:
Windows::Storage::Streams::DataReader ^ m_dataReader;
COpndCommand DeserializeOperand();
CParentheses DeserializeParentheses();
CUnaryCommand DeserializeUnary();
CBinaryCommand DeserializeBinary();
};
}
}

View file

@ -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);
}

View file

@ -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;
};
}
}

View file

@ -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<int, multimap<wchar_t, WeakReference>> s_CharacterForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeysForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyControlChordsForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyShiftChordsForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyAltChordsForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyControlShiftChordsForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyInverseChordsForButtons;
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyControlInverseChordsForButtons;
static multimap<int, bool> s_ShiftKeyPressed;
static multimap<int, bool> s_ControlKeyPressed;
static multimap<int, bool> s_ShiftButtonChecked;
static multimap<int, bool> 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 <typename T>
void LightUpButtons(const T& buttons)
{
auto iterator = buttons.first;
for (; iterator != buttons.second; ++iterator)
{
auto button = iterator->second.Resolve<ButtonBase>();
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<ToggleButton ^>(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<Object ^>([buttonWeakReference, timerWeakReference](Object ^, Object ^) {
auto button = buttonWeakReference.Resolve<ButtonBase>();
if (button)
{
VisualStateManager::GoToState(button, "Normal", true);
}
// Cancel the timer after we're done so it only fires once
auto timer = timerWeakReference.Resolve<DispatcherTimer>();
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 <typename T>
void RunFirstEnabledButtonCommand(const T& buttons)
{
auto buttonIterator = buttons.first;
for (; buttonIterator != buttons.second; ++buttonIterator)
{
auto button = buttonIterator->second.Resolve<ButtonBase>();
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<RadioButton ^>(button);
if (radio)
{
radio->IsChecked = true;
return;
}
auto toggle = dynamic_cast<ToggleButton ^>(button);
if (toggle)
{
toggle->IsChecked = !toggle->IsChecked->Value;
return;
}
}
}
}
}
static multimap<int, bool> s_ignoreNextEscape;
static multimap<int, bool> s_keepIgnoringEscape;
static multimap<int, bool> s_fHonorShortcuts;
static multimap<int, bool> s_fHandledEnter;
static multimap<int, Flyout ^> 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<ButtonBase ^>(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<wchar_t, WeakReference>()));
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<ButtonBase ^>(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<MyVirtualKey, WeakReference>()));
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<ButtonBase ^>(target);
if (control == nullptr)
{
// Handling Ctrl+E shortcut for Date Calc, target would be NavigationView^ in that case
control = safe_cast<MUXC::NavigationView ^>(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<MyVirtualKey, WeakReference>()));
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<ButtonBase ^>(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<MyVirtualKey, WeakReference>()));
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<MUXC::NavigationView ^>(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<MyVirtualKey, WeakReference>()));
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<ButtonBase ^>(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<MyVirtualKey, WeakReference>()));
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<ButtonBase ^>(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<MyVirtualKey, WeakReference>()));
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<ButtonBase ^>(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<MyVirtualKey, WeakReference>()));
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<wchar_t>(args->KeyCode);
auto buttons = s_CharacterForButtons.find(viewId)->second.equal_range(character);
RunFirstEnabledButtonCommand(buttons);
LightUpButtons(buttons);
}
}
}
const std::multimap<MyVirtualKey, WeakReference>& 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<MyVirtualKey>(key));
auto buttons = lookupMap.equal_range(static_cast<MyVirtualKey>(key));
auto navView = buttons.first->second.Resolve<MUXC::NavigationView>();
auto appViewModel = safe_cast<ApplicationViewModel ^>(navView->DataContext);
appViewModel->Mode = ViewMode::Date;
auto categoryName = AppResourceProvider::GetInstance().GetResourceString(L"DateCalculationModeText");
appViewModel->CategoryName = categoryName;
auto menuItems = static_cast<IObservableVector<Object ^> ^>(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<MyVirtualKey>(key));
auto buttons = lookupMap.equal_range(static_cast<MyVirtualKey>(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<MyVirtualKey>(key), altPressed);
auto listItems = lookupMap.equal_range(static_cast<MyVirtualKey>(key));
for (auto listIterator = listItems.first; listIterator != listItems.second; ++listIterator)
{
auto item = listIterator->second.Resolve<MUXC::NavigationView>();
if (item != nullptr)
{
auto navView = safe_cast<MUXC::NavigationView ^>(item);
auto menuItems = static_cast<IObservableVector<Object ^> ^>(navView->MenuItemsSource);
if (menuItems != nullptr)
{
auto vm = safe_cast<ApplicationViewModel ^>(navView->DataContext);
if (nullptr != vm)
{
ViewMode toMode = NavCategory::GetViewModeForVirtualKey(static_cast<MyVirtualKey>(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<CoreWindow ^, CharacterReceivedEventArgs ^>(&KeyboardShortcutManager::OnCharacterReceivedHandler);
coreWindow->KeyDown += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(&KeyboardShortcutManager::OnKeyDownHandler);
coreWindow->KeyUp += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(&KeyboardShortcutManager::OnKeyUpHandler);
coreWindow->Dispatcher->AcceleratorKeyActivated +=
ref new TypedEventHandler<CoreDispatcher ^, AcceleratorKeyEventArgs ^>(&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<wchar_t, WeakReference>()));
}
if (s_VirtualKeysForButtons.find(appViewId) == s_VirtualKeysForButtons.end())
{
s_VirtualKeysForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyControlChordsForButtons.find(appViewId) == s_VirtualKeyControlChordsForButtons.end())
{
s_VirtualKeyControlChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyShiftChordsForButtons.find(appViewId) == s_VirtualKeyShiftChordsForButtons.end())
{
s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyAltChordsForButtons.find(appViewId) == s_VirtualKeyAltChordsForButtons.end())
{
s_VirtualKeyAltChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end())
{
s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyInverseChordsForButtons.find(appViewId) == s_VirtualKeyInverseChordsForButtons.end())
{
s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyControlInverseChordsForButtons.find(appViewId) == s_VirtualKeyControlInverseChordsForButtons.end())
{
s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
}
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);
}

View file

@ -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);
};
}
}

View file

@ -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<Control ^>(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<TextBlock ^>(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<RichTextBlock ^>(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<TextElement ^>(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<String ^> ^ 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<String ^> ^ 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<String ^> ^ 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<String ^> ^ 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<String ^> ^ 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<String ^>();
languageList->Append(localeString);
return languageList;
}
}
return nullptr;
}
unordered_map<wstring, wstring> 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<pair<wstring, wstring>> s_parenEngineKeyResourceMap = { // Sine permutations
make_pair<wstring, wstring>(L"67", L"SineDegrees"),
make_pair<wstring, wstring>(L"73", L"SineRadians"),
make_pair<wstring, wstring>(L"79", L"SineGradians"),
make_pair<wstring, wstring>(L"70", L"InverseSineDegrees"),
make_pair<wstring, wstring>(L"76", L"InverseSineRadians"),
make_pair<wstring, wstring>(L"82", L"InverseSineGradians"),
make_pair<wstring, wstring>(L"25", L"HyperbolicSine"),
make_pair<wstring, wstring>(L"85", L"InverseHyperbolicSine"),
// Cosine permutations
make_pair<wstring, wstring>(L"68", L"CosineDegrees"),
make_pair<wstring, wstring>(L"74", L"CosineRadians"),
make_pair<wstring, wstring>(L"80", L"CosineGradians"),
make_pair<wstring, wstring>(L"71", L"InverseCosineDegrees"),
make_pair<wstring, wstring>(L"77", L"InverseCosineRadians"),
make_pair<wstring, wstring>(L"83", L"InverseCosineGradians"),
make_pair<wstring, wstring>(L"26", L"HyperbolicCosine"),
make_pair<wstring, wstring>(L"86", L"InverseHyperbolicCosine"),
// Tangent permutations
make_pair<wstring, wstring>(L"69", L"TangentDegrees"),
make_pair<wstring, wstring>(L"75", L"TangentRadians"),
make_pair<wstring, wstring>(L"81", L"TangentGradians"),
make_pair<wstring, wstring>(L"72", L"InverseTangentDegrees"),
make_pair<wstring, wstring>(L"78", L"InverseTangentRadians"),
make_pair<wstring, wstring>(L"84", L"InverseTangentGradians"),
make_pair<wstring, wstring>(L"27", L"HyperbolicTangent"),
make_pair<wstring, wstring>(L"87", L"InverseHyperbolicTangent"),
// Miscellaneous Scientific functions
make_pair<wstring, wstring>(L"94", L"Factorial"),
make_pair<wstring, wstring>(L"35", L"DegreeMinuteSecond"),
make_pair<wstring, wstring>(L"28", L"NaturalLog"),
make_pair<wstring, wstring>(L"91", L"Square")
};
static vector<pair<wstring, wstring>> s_noParenEngineKeyResourceMap = { // Programmer mode functions
make_pair<wstring, wstring>(L"9", L"LeftShift"),
make_pair<wstring, wstring>(L"10", L"RightShift"),
// Y Root scientific function
make_pair<wstring, wstring>(L"16", L"YRoot")
};
unordered_map<wstring, wstring> 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<wstring, wstring> 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());
}

View file

@ -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<Platform::String ^> ^ 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<std::wstring, std::wstring> 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;
};
}
}

View file

@ -1,379 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "LocalizationService.h"
#include <iterator>
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<int>(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<int>(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<int>(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<int>(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)&currencyTrailingDigits,
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)&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<PWSTR>(&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<PWSTR>(day), // Argument is of type PWSTR
static_cast<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 = static_cast<Windows::Globalization::DayOfWeek>((_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<wchar_t[]> 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<wchar_t, 10> m_digitSymbols;
// Hexadecimal characters are not currently localized
static constexpr std::array<wchar_t, 6> 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;
};
}
}

View file

@ -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<wchar_t[]> spBuffer = std::unique_ptr<wchar_t[]>(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 <typename... T>
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);
}
};
}
}

View file

@ -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<const NavCategoryGroupInitializer, 2> 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<const NavCategoryInitializer, 17> 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<Box<int> ^>(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<MyVirtualKey> NavCategory::GetCategoryAcceleratorKeys()
{
vector<MyVirtualKey> 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<NavCategory ^>())
{
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 ^> ^ NavCategoryGroup::CreateMenuOptions()
{
auto menuOptions = ref new Vector<NavCategoryGroup ^>();
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<NavCategoryInitializer> NavCategoryGroup::GetInitializerCategoryGroup(CategoryGroupType groupType)
{
vector<NavCategoryInitializer> 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;
}

View file

@ -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<MyVirtualKey> 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<NavCategory ^> ^, Categories);
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
static Platform::String ^ GetHeaderResourceKey(CategoryGroupType type);
internal : static NavCategoryGroup ^ CreateCalculatorCategory();
static NavCategoryGroup ^ CreateConverterCategory();
private:
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
static std::vector<NavCategoryInitializer> GetInitializerCategoryGroup(CategoryGroupType groupType);
};
}
}

View file

@ -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;
}

View file

@ -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;
};
}

View file

@ -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;
};
}

File diff suppressed because it is too large Load diff

View file

@ -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<TraceActivity> 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> 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<int, int> bitLengthButtonUsage;
std::map<int, int> angleButtonUsage;
std::map<int, int> radixButtonUsage;
std::map<int, bool> windowIdLog;
// Private variables for Date Calculator usage
bool m_dateDiffUsageLoggedInSession = false;
bool m_dateAddUsageLoggedInSession = false;
bool m_dateSubtractUsageLoggedInSession = false;
std::map<int, int> m_dateAddModeUsage;
std::map<int, int> m_dateSubtractModeUsage;
size_t windowLaunchCount = 0;
winrt::Windows::Foundation::Diagnostics::LoggingActivity m_appLaunchActivity;
};
}

View file

@ -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<void()>&& 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<CalculatorVector<pair<wstring, int>>> const& tokens,
_In_ shared_ptr<CalculatorVector<shared_ptr<IExpressionCommand>>> 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<IExpressionCommand> exprCmd;
IFTPlatformException(commands->GetAt(i, &exprCmd));
CalculationManager::CommandType commandType = exprCmd->GetCommandType();
writer->WriteInt32(static_cast<int>(commandType));
exprCmd->Accept(cmdVisitor);
}
unsigned int tokensSize;
IFTPlatformException(tokens->GetSize(&tokensSize));
writer->WriteUInt32(tokensSize);
for (unsigned int i = 0; i < tokensSize; ++i)
{
pair<wstring, int> 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<CalculatorVector<shared_ptr<IExpressionCommand>>> Utils::DeserializeCommands(DataReader ^ reader)
{
shared_ptr<CalculatorVector<shared_ptr<IExpressionCommand>>> commandVector = make_shared<CalculatorVector<shared_ptr<IExpressionCommand>>>();
auto commandVectorSize = reader->ReadUInt32();
CommandDeserializer cmdDeserializer(reader);
for (unsigned int i = 0; i < commandVectorSize; ++i)
{
auto commandTypeInt = reader->ReadInt32();
CalculationManager::CommandType commandType = static_cast<CalculationManager::CommandType>(commandTypeInt);
shared_ptr<IExpressionCommand> exprCmd = cmdDeserializer.Deserialize(commandType);
commandVector->Append(exprCmd);
}
return commandVector;
}
const shared_ptr<CalculatorVector<pair<wstring, int>>> Utils::DeserializeTokens(DataReader ^ reader)
{
shared_ptr<CalculatorVector<pair<wstring, int>>> tokenVector = make_shared<CalculatorVector<pair<wstring, int>>>();
auto tokensSize = reader->ReadUInt32();
for (unsigned int i = 0; i < tokensSize; ++i)
{
pair<wstring, int> 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<void> 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<String ^> 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;
}

View file

@ -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_<n>
#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<t>(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 <typename T>
struct IsRefClass
{
static const bool value = __is_ref_class(T);
};
template <typename T>
struct RemoveHat
{
typedef T type;
};
template <typename T>
struct RemoveHat<T ^>
{
typedef T type;
};
template <typename T>
typename std::enable_if<IsRefClass<T>::value, T ^>::type MakeDefault()
{
return nullptr;
}
template <typename T>
typename std::enable_if<!IsRefClass<T>::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 <typename T>
struct TypeToUseForDependencyProperty
{
typedef typename std::conditional<std::is_enum<T>::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 <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(
_In_ const wchar_t* const name,
_In_ Windows::UI::Xaml::PropertyMetadata^ metadata)
{
typedef typename Details::RemoveHat<TOwner>::type OwnerType;
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
typedef typename Details::TypeToUseForDependencyProperty<ThisPropertyType>::type ThisDependencyPropertyType;
static_assert(Details::IsRefClass<OwnerType>::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 <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name)
{
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
return RegisterDependencyProperty<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault<ThisPropertyType>()));
}
template <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name, TType defaultValue)
{
return RegisterDependencyProperty<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(defaultValue));
}
template <typename TOwner, typename TType, typename TCallback>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback(
_In_ wchar_t const * const name,
TCallback callback)
{
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
return RegisterDependencyProperty<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(
Details::MakeDefault<ThisPropertyType>(),
ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
}
template <typename TOwner, typename TType, typename TCallback>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback(
_In_ wchar_t const * const name,
TType defaultValue,
TCallback callback)
{
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
return RegisterDependencyProperty<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(
defaultValue,
ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
}
// Attached DependencyProperty
template <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(
_In_ const wchar_t* const name,
_In_ Windows::UI::Xaml::PropertyMetadata^ metadata)
{
typedef typename Details::RemoveHat<TOwner>::type OwnerType;
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
typedef typename Details::TypeToUseForDependencyProperty<ThisPropertyType>::type ThisDependencyPropertyType;
static_assert(Details::IsRefClass<OwnerType>::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 <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name)
{
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
return RegisterDependencyPropertyAttached<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault<ThisPropertyType>()));
}
template <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name, TType defaultValue)
{
return RegisterDependencyPropertyAttached<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(defaultValue));
}
template <typename TOwner, typename TType, typename TCallback>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback(
_In_ wchar_t const * const name,
TCallback callback)
{
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
return RegisterDependencyPropertyAttached<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(
Details::MakeDefault<ThisPropertyType>(),
ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
}
template <typename TOwner, typename TType, typename TCallback>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback(
_In_ wchar_t const * const name,
TType defaultValue,
TCallback callback)
{
typedef typename Details::RemoveHat<TType>::type ThisPropertyType;
return RegisterDependencyPropertyAttached<TOwner, TType>(
name,
ref new Windows::UI::Xaml::PropertyMetadata(
defaultValue,
ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
}
template <typename T>
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<void()>&& function, _In_ Windows::UI::Core::CoreDispatcher ^ currentDispatcher);
void SerializeCommandsAndTokens(
_In_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const& tokens,
_In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const& commands,
Windows::Storage::Streams::DataWriter ^ writer);
const std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> DeserializeCommands(Windows::Storage::Streams::DataReader ^ reader);
const std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> DeserializeTokens(Windows::Storage::Streams::DataReader ^ reader);
Windows::Foundation::DateTime GetUniversalSystemTime();
bool IsDateTimeOlderThan(Windows::Foundation::DateTime dateTime, const long long duration);
concurrency::task<void> WriteFileToFolder(
Windows::Storage::IStorageFolder ^ folder,
Platform::String ^ fileName,
Platform::String ^ contents,
Windows::Storage::CreationCollisionOption collisionOption);
concurrency::task<Platform::String ^> 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<type>(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<DependencyPropertiesOwner, type>(L#name); \
} \
\
public:
#define DEPENDENCY_PROPERTY_WITH_DEFAULT(type, name, defaultValue) \
property type name \
{ \
type get() \
{ \
return safe_cast<type>(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<DependencyPropertiesOwner, type>(L#name, defaultValue); \
} \
\
public:
#define DEPENDENCY_PROPERTY_WITH_CALLBACK(type, name) \
property type name \
{ \
type get() \
{ \
return safe_cast<type>(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<DependencyPropertiesOwner, type>(L#name, &On##name##PropertyChangedImpl); \
} \
static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \
{ \
auto self = safe_cast<DependencyPropertiesOwner ^>(sender); \
self->On##name##PropertyChanged(safe_cast<type>(args->OldValue), safe_cast<type>(args->NewValue)); \
} \
\
public:
#define DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \
property type name \
{ \
type get() \
{ \
return safe_cast<type>(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<DependencyPropertiesOwner, type>(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<DependencyPropertiesOwner ^>(sender); \
self->On##name##PropertyChanged(safe_cast<type>(args->OldValue), safe_cast<type>(args->NewValue)); \
} \
\
public:
// Attached DependencyProperty
#define DEPENDENCY_PROPERTY_ATTACHED(type, name) \
static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \
{ \
return safe_cast<type>(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<DependencyPropertiesOwner, type>(L#name); \
} \
\
public:
#define DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT(type, name, defaultValue) \
static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \
{ \
return safe_cast<type>(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<DependencyPropertiesOwner, type>(L#name, defaultValue); \
} \
\
public:
#define DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(type, name) \
static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \
{ \
return safe_cast<type>(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<DependencyPropertiesOwner, type>(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<type>(args->OldValue), safe_cast<type>(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<type>(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<DependencyPropertiesOwner, type>(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<type>(args->OldValue), safe_cast<type>(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 <typename T>
T from_cx(Platform::Object ^ from)
{
T to{ nullptr };
winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)->QueryInterface(winrt::guid_of<T>(), reinterpret_cast<void**>(winrt::put_abi(to))));
return to;
}
}

View file

@ -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<Windows::Foundation::IPropertyValue ^>(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;
}
};
}
}

View file

@ -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<wstring_view, 5> 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<wstring_view, 2> 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<ICurrencyHttpClient> 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<int>(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<bool> {
vector<function<task<bool>()>> 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<UCM::Category> CurrencyDataLoader::LoadOrderedCategories()
{
// This function should not be called
// The model will use the categories from UnitConverterDataLoader
return vector<UCM::Category>();
}
vector<UCM::Unit> CurrencyDataLoader::LoadOrderedUnits(const UCM::Category& /*category*/)
{
lock_guard<mutex> lock(m_currencyUnitsMutex);
return m_currencyUnits;
}
unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> CurrencyDataLoader::LoadOrderedRatios(const UCM::Unit& unit)
{
lock_guard<mutex> 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<UCM::IViewModelCurrencyCallback>& callback)
{
m_vmCallback = callback;
OnNetworkBehaviorChanged(m_networkAccessBehavior);
}
pair<wstring, wstring> CurrencyDataLoader::GetCurrencySymbols(const UCM::Unit& unit1, const UCM::Unit& unit2)
{
lock_guard<mutex> 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<wstring, wstring> 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<UCM::Unit, UCM::ConversionData, UCM::UnitHash> 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<int>(ratio * static_cast<int>(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<bool> 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<DateTime>(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<bool> CurrencyDataLoader::TryFinishLoadFromCacheAsync()
{
auto localSettings = ApplicationData::Current->LocalSettings;
if (localSettings == nullptr)
{
co_return false;
}
if (!localSettings->Values->HasKey(CacheLangcodeKey) || !static_cast<String ^>(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<UCM::CurrencyStaticData> 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<bool> 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<UCM::CurrencyStaticData> 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<pair<String ^, String ^>> 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<bool> 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<UCM::CurrencyStaticData>& staticData,
_Inout_ CurrencyRatioMap& allRatiosData)
{
return TryParseStaticData(staticDataJson, staticData) && TryParseAllRatiosData(allRatiosJson, allRatiosData);
}
bool CurrencyDataLoader::TryParseStaticData(_In_ String ^ rawJson, _Inout_ vector<UCM::CurrencyStaticData>& 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<wstring*> values = { &countryCode, &countryName, &currencyCode, &currencyName, &currencySymbol };
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<void> CurrencyDataLoader::FinalizeUnits(_In_ const vector<UCM::CurrencyStaticData>& staticData, _In_ const CurrencyRatioMap& ratioMap)
{
unordered_map<int, pair<UCM::Unit, double>> idToUnit{};
SelectedUnits defaultCurrencies = co_await GetDefaultFromToCurrency();
wstring fromCurrency = defaultCurrencies.first;
wstring toCurrency = defaultCurrencies.second;
{
lock_guard<mutex> 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<int>(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<int, pair<UCM::Unit, double>>(unit.id, pair<UCM::Unit, double>(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<UCM::Unit, UCM::ConversionData, UCM::UnitHash> 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<SelectedUnits> 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<String ^>(values->Lookup(fromKey))->Data();
*toCurrency = static_cast<String ^>(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()));
}
}

View file

@ -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<std::wstring, UCM::CurrencyRatio> CurrencyRatioMap;
typedef std::pair<std::wstring, std::wstring> 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<CalculatorApp::DataLoaders::ICurrencyHttpClient> client);
~CurrencyDataLoader();
bool LoadFinished();
bool LoadedFromCache();
bool LoadedFromWeb();
// IConverterDataLoader
void LoadData() override;
std::vector<UCM::Category> LoadOrderedCategories() override;
std::vector<UCM::Unit> LoadOrderedUnits(const UCM::Category& category) override;
std::unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> LoadOrderedRatios(const UCM::Unit& unit) override;
bool SupportsCategory(const UnitConversionManager::Category& target) override;
// IConverterDataLoader
// ICurrencyConverterDataLoader
void SetViewModelCallback(const std::shared_ptr<UCM::IViewModelCurrencyCallback>& callback) override;
std::pair<std::wstring, std::wstring> GetCurrencySymbols(const UCM::Unit& unit1, const UCM::Unit& unit2) override;
std::pair<std::wstring, std::wstring>
GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override;
std::wstring GetCurrencyTimestamp() override;
concurrency::task<bool> TryLoadDataFromCacheAsync() override;
concurrency::task<bool> TryLoadDataFromWebAsync() override;
concurrency::task<bool> TryLoadDataFromWebOverrideAsync() override;
// ICurrencyConverterDataLoader
void OnNetworkBehaviorChanged(CalculatorApp::NetworkAccessBehavior newBehavior);
private:
void ResetLoadStatus();
void NotifyDataLoadFinished(bool didLoad);
concurrency::task<bool> TryFinishLoadFromCacheAsync();
bool TryParseWebResponses(
_In_ Platform::String ^ staticDataJson,
_In_ Platform::String ^ allRatiosJson,
_Inout_ std::vector<UCM::CurrencyStaticData>& staticData,
_Inout_ CurrencyRatioMap& allRatiosData);
bool TryParseStaticData(_In_ Platform::String ^ rawJson, _Inout_ std::vector<UCM::CurrencyStaticData>& staticData);
bool TryParseAllRatiosData(_In_ Platform::String ^ rawJson, _Inout_ CurrencyRatioMap& allRatiosData);
concurrency::task<void> FinalizeUnits(_In_ const std::vector<UCM::CurrencyStaticData>& staticData, _In_ const CurrencyRatioMap& ratioMap);
void GuaranteeSelectedUnits();
void SaveLangCodeAndTimestamp();
void UpdateDisplayedTimestamp();
void RegisterForNetworkBehaviorChanges();
void UnregisterForNetworkBehaviorChanges();
concurrency::task<SelectedUnits> 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<CalculatorApp::DataLoaders::ICurrencyHttpClient> m_client;
bool m_isRtlLanguage;
std::mutex m_currencyUnitsMutex;
std::vector<UCM::Unit> m_currencyUnits;
UCM::UnitToUnitToConversionDataMap m_currencyRatioMap;
std::unordered_map<UCM::Unit, CurrencyUnitMetadata, UCM::UnitHash> m_currencyMetadata;
std::shared_ptr<UCM::IViewModelCurrencyCallback> 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;
};
}
}

View file

@ -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<String ^, HttpProgress> ^ 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<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyRatios()
{
wstring uri = wstring{ sc_RatiosUriRelativeTo } + m_sourceCurrencyCode->Data();
auto ratiosUri = ref new Uri(StringReference(uri.c_str()));
return m_client->GetStringAsync(ratiosUri);
}

View file

@ -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<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() override;
Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() override;
private:
Windows::Web::Http::HttpClient ^ m_client;
Platform::String ^ m_responseLanguage;
Platform::String ^ m_sourceCurrencyCode;
};
}
}

View file

@ -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"
}
}

View file

@ -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<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() = 0;
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() = 0;
};
}
}

View file

@ -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
};
}
}

Some files were not shown because too many files have changed in this diff Show more