mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-22 14:13:30 -07:00
parent
9f01c8168b
commit
20668f8f03
782 changed files with 24953 additions and 47110 deletions
126
src/CalcManager/CCalcManager.cpp
Normal file
126
src/CalcManager/CCalcManager.cpp
Normal 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);
|
||||
}
|
58
src/CalcManager/CCalcManager.h
Normal file
58
src/CalcManager/CCalcManager.h
Normal 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);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
#include <sstream>
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CalcEngine;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "Header Files/CalcUtils.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "headers/CalcUtils.h"
|
||||
|
||||
bool IsOpInRange(OpCode op, uint32_t x, uint32_t y)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "Command.h"
|
||||
#include "CalculatorVector.h"
|
||||
#include "ExpressionCommand.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
#include <algorithm>
|
||||
#include "Header Files/Number.h"
|
||||
#include "headers/Number.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
#include <intsafe.h>
|
||||
#include "Header Files/Rational.h"
|
||||
//#include <intsafe.h>
|
||||
#include "headers/Rational.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Header Files/RationalMath.h"
|
||||
#include "headers/RationalMath.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CalcEngine;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
#include <cassert>
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "CalculatorResource.h"
|
||||
|
||||
using namespace std;
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
\****************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "Header Files/CalcUtils.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "headers/CalcUtils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CalcEngine;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CalcEngine;
|
||||
|
@ -48,7 +48,6 @@ typedef struct
|
|||
bool bUseSep;
|
||||
} LASTDISP;
|
||||
|
||||
LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
|
||||
|
||||
// Truncates if too big, makes it a non negative - the number in rat. Doesn't do anything if not in INT mode
|
||||
CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational const& rat)
|
||||
|
@ -77,6 +76,8 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con
|
|||
|
||||
void CCalcEngine::DisplayNum(void)
|
||||
{
|
||||
static LASTDISP gldPrevious = { 0, -1, 0, -1, (NUM_WIDTH)-1, false, false, false };
|
||||
|
||||
//
|
||||
// Only change the display if
|
||||
// we are in record mode -OR-
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
/*** ***/
|
||||
/*** ***/
|
||||
/**************************************************************************/
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace CalcEngine;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
|
||||
using namespace CalcEngine;
|
||||
using namespace CalcEngine::RationalMath;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
|
||||
using namespace CalcEngine;
|
||||
using namespace CalcEngine::RationalMath;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<RootNamespace>CalcManager</RootNamespace>
|
||||
<DisableAppLocalVCLibs>false</DisableAppLocalVCLibs>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
|
||||
<MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
|
@ -56,46 +56,46 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
|
@ -158,6 +158,7 @@
|
|||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
|
||||
<PreprocessorDefinitions>_UNICODE;UNICODE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -222,7 +223,7 @@
|
|||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<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>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
|
@ -290,21 +291,23 @@
|
|||
<ClInclude Include="CalculatorManager.h" />
|
||||
<ClInclude Include="CalculatorResource.h" />
|
||||
<ClInclude Include="CalculatorVector.h" />
|
||||
<ClInclude Include="CCalcManager.h" />
|
||||
<ClInclude Include="Command.h" />
|
||||
<ClInclude Include="compat.h" />
|
||||
<ClInclude Include="ExpressionCommand.h" />
|
||||
<ClInclude Include="ExpressionCommandInterface.h" />
|
||||
<ClInclude Include="Header Files\CalcEngine.h" />
|
||||
<ClInclude Include="Header Files\CalcUtils.h" />
|
||||
<ClInclude Include="Header Files\CCommand.h" />
|
||||
<ClInclude Include="Header Files\EngineStrings.h" />
|
||||
<ClInclude Include="Header Files\History.h" />
|
||||
<ClInclude Include="Header Files\ICalcDisplay.h" />
|
||||
<ClInclude Include="Header Files\CalcInput.h" />
|
||||
<ClInclude Include="Header Files\IHistoryDisplay.h" />
|
||||
<ClInclude Include="Header Files\Number.h" />
|
||||
<ClInclude Include="Header Files\RadixType.h" />
|
||||
<ClInclude Include="Header Files\Rational.h" />
|
||||
<ClInclude Include="Header Files\RationalMath.h" />
|
||||
<ClInclude Include="headers\CalcEngine.h" />
|
||||
<ClInclude Include="headers\CalcInput.h" />
|
||||
<ClInclude Include="headers\CalcUtils.h" />
|
||||
<ClInclude Include="headers\CCommand.h" />
|
||||
<ClInclude Include="headers\EngineStrings.h" />
|
||||
<ClInclude Include="headers\History.h" />
|
||||
<ClInclude Include="headers\ICalcDisplay.h" />
|
||||
<ClInclude Include="headers\IHistoryDisplay.h" />
|
||||
<ClInclude Include="headers\Number.h" />
|
||||
<ClInclude Include="headers\RadixType.h" />
|
||||
<ClInclude Include="headers\Rational.h" />
|
||||
<ClInclude Include="headers\RationalMath.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Ratpack\CalcErr.h" />
|
||||
<ClInclude Include="Ratpack\ratconst.h" />
|
||||
|
@ -314,6 +317,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="CalculatorHistory.cpp" />
|
||||
<ClCompile Include="CalculatorManager.cpp" />
|
||||
<ClCompile Include="CCalcManager.cpp" />
|
||||
<ClCompile Include="CEngine\calc.cpp" />
|
||||
<ClCompile Include="CEngine\CalcUtils.cpp" />
|
||||
<ClCompile Include="CEngine\History.cpp" />
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Filter Include="RatPack">
|
||||
<UniqueIdentifier>{a1bae6f0-0a01-447d-9a3a-5c65bcd384e6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<Filter Include="headers">
|
||||
<UniqueIdentifier>{5149465e-c5c9-48a2-b676-f11380b733a0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
|
@ -89,27 +89,13 @@
|
|||
<ClCompile Include="CEngine\RationalMath.cpp">
|
||||
<Filter>CEngine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CCalcManager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Command.h" />
|
||||
<ClInclude Include="ExpressionCommand.h" />
|
||||
<ClInclude Include="ExpressionCommandInterface.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">
|
||||
<Filter>RatPack</Filter>
|
||||
</ClInclude>
|
||||
|
@ -120,45 +106,49 @@
|
|||
<Filter>RatPack</Filter>
|
||||
</ClInclude>
|
||||
<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="CalculatorHistory.h" />
|
||||
<ClInclude Include="CalculatorManager.h" />
|
||||
<ClInclude Include="CalculatorResource.h" />
|
||||
<ClInclude Include="Header Files\ICalcDisplay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\CalcEngine.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Header Files\CalcInput.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\CalcInput.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Header Files\IHistoryDisplay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\CalcUtils.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Header Files\Number.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\CCommand.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Header Files\Rational.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\EngineStrings.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Header Files\RadixType.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\History.h">
|
||||
<Filter>headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Header Files\RationalMath.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<ClInclude Include="headers\ICalcDisplay.h">
|
||||
<Filter>headers</Filter>
|
||||
</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>
|
||||
</Project>
|
||||
</Project>
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
#include "ExpressionCommandInterface.h"
|
||||
#include "Header Files/IHistoryDisplay.h"
|
||||
#include "headers/IHistoryDisplay.h"
|
||||
|
||||
namespace CalculationManager
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
#include <climits> // for UCHAR_MAX
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "CalculatorManager.h"
|
||||
#include "CalculatorResource.h"
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "CalculatorHistory.h"
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "Header Files/Rational.h"
|
||||
#include "Header Files/ICalcDisplay.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "headers/Rational.h"
|
||||
#include "headers/ICalcDisplay.h"
|
||||
|
||||
namespace CalculationManager
|
||||
{
|
||||
|
@ -153,4 +153,4 @@ namespace CalculationManager
|
|||
void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector<std::shared_ptr<HISTORYITEM>> const& history);
|
||||
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -5,10 +5,17 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <winerror.h>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include "Ratpack/CalcErr.h"
|
||||
#include <stdexcept> // for std::out_of_range
|
||||
|
||||
#if !defined(__WEBASSEMBLY__)
|
||||
#include <winerror.h>
|
||||
#include <sal.h> // for SAL
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
template <typename TType>
|
||||
class CalculatorVector
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
#include <string>
|
||||
#include "Header Files/CCommand.h"
|
||||
#include "headers/CCommand.h"
|
||||
#include "CalculatorVector.h"
|
||||
#include "ExpressionCommand.h"
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#pragma once
|
||||
#include "ExpressionCommandInterface.h"
|
||||
#include "Header Files/CalcEngine.h"
|
||||
#include "Header Files/Rational.h"
|
||||
#include "headers/CalcEngine.h"
|
||||
#include "headers/Rational.h"
|
||||
|
||||
class CParentheses final : public IParenthesisCommand
|
||||
{
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <winerror.h>
|
||||
// #include <winerror.h>
|
||||
#include <sstream>
|
||||
#include <cstring> // for memmove, memcpy
|
||||
#include "ratpak.h"
|
||||
#include "compat.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -48,7 +49,7 @@ wchar_t g_decimalSeparator = L'.';
|
|||
#define Calc_UInt32x32To64(a, b) ((uint64_t)((uint32_t)(a)) * (uint64_t)((uint32_t)(b)))
|
||||
#endif
|
||||
|
||||
#elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM)
|
||||
#elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) || defined(__EMSCRIPTEN__)
|
||||
|
||||
#ifndef Calc_UInt32x32To64
|
||||
#define Calc_UInt32x32To64(a, b) (uint64_t)((uint64_t)(uint32_t)(a) * (uint32_t)(b))
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,8 @@
|
|||
#include <string>
|
||||
#include "CalcErr.h"
|
||||
#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 BASEX = 0x80000000; // Internal radix used in calculations, hope to raise
|
||||
|
|
30
src/CalcManager/compat.h
Normal file
30
src/CalcManager/compat.h
Normal 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
|
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
inline constexpr auto IDS_ERRORS_FIRST = 99;
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include "ICalcDisplay.h"
|
||||
#include "IHistoryDisplay.h"
|
||||
#include "Rational.h"
|
||||
#include "compat.h"
|
||||
|
||||
// maximum depth you can get by precedence. It is just an array's size limit.
|
||||
static constexpr size_t MAXPRECDEPTH = 25;
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Number.h"
|
||||
#include "compat.h"
|
||||
|
||||
namespace CalcEngine
|
||||
{
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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)
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -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)¤cyTrailingDigits,
|
||||
sizeof(currencyTrailingDigits) / sizeof(WCHAR));
|
||||
if (result == 0)
|
||||
{
|
||||
throw std::runtime_error("Unexpected error while getting locale info");
|
||||
}
|
||||
|
||||
// Currency symbol precedence is either 0 or 1.
|
||||
// A value of 0 indicates the symbol follows the currency value.
|
||||
int currencySymbolPrecedence = 1;
|
||||
result = GetLocaleInfoEx(
|
||||
LOCALE_NAME_USER_DEFAULT,
|
||||
LOCALE_IPOSSYMPRECEDES | LOCALE_RETURN_NUMBER,
|
||||
(LPWSTR)¤cySymbolPrecedence,
|
||||
sizeof(currencySymbolPrecedence) / sizeof(WCHAR));
|
||||
|
||||
// As CalcEngine only supports the first character of the decimal separator,
|
||||
// Only first character of the decimal separator string is supported.
|
||||
m_decimalSeparator = decimalString[0];
|
||||
m_numberGroupSeparator = groupingSymbolString[0];
|
||||
m_numberGrouping = numberGroupingString;
|
||||
m_listSeparator = listSeparatorString;
|
||||
m_currencyTrailingDigits = currencyTrailingDigits;
|
||||
m_currencySymbolPrecedence = currencySymbolPrecedence;
|
||||
}
|
||||
|
||||
// Get the system calendar type
|
||||
// Note: This function returns 0 on failure.
|
||||
// We'll ignore the failure in that case and the CalendarIdentifier would get set to GregorianCalendar.
|
||||
CALID calId;
|
||||
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER, reinterpret_cast<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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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, ¤cyCode, ¤cyName, ¤cySymbol };
|
||||
|
||||
assert(values.size() == STATIC_DATA_PROPERTIES.size());
|
||||
staticData.resize(size_t{ data->Size });
|
||||
for (unsigned int i = 0; i < data->Size; i++)
|
||||
{
|
||||
JsonObject ^ obj = data->GetAt(i)->GetObject();
|
||||
|
||||
for (size_t j = 0; j < values.size(); j++)
|
||||
{
|
||||
(*values[j]) = obj->GetNamedString(StringReference(STATIC_DATA_PROPERTIES[j].data()))->Data();
|
||||
}
|
||||
|
||||
staticData[i] = CurrencyStaticData{ countryCode, countryName, currencyCode, currencyName, currencySymbol };
|
||||
}
|
||||
|
||||
// TODO - MSFT 8533667: this sort will be replaced by a WinRT call to sort localized strings
|
||||
sort(begin(staticData), end(staticData), [](CurrencyStaticData unit1, CurrencyStaticData unit2) { return unit1.countryName < unit2.countryName; });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String ^ rawJson, _Inout_ CurrencyRatioMap& allRatios)
|
||||
{
|
||||
JsonArray ^ data = nullptr;
|
||||
if (!JsonArray::TryParse(rawJson, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring sourceCurrencyCode{ DefaultCurrencyCode };
|
||||
|
||||
allRatios.clear();
|
||||
for (unsigned int i = 0; i < data->Size; i++)
|
||||
{
|
||||
JsonObject ^ obj = data->GetAt(i)->GetObject();
|
||||
|
||||
// Rt is ratio, An is target currency ISO code.
|
||||
double relativeRatio = obj->GetNamedNumber(StringReference(RATIO_KEY));
|
||||
wstring targetCurrencyCode = obj->GetNamedString(StringReference(CURRENCY_CODE_KEY))->Data();
|
||||
|
||||
allRatios.emplace(targetCurrencyCode, CurrencyRatio{ relativeRatio, sourceCurrencyCode, targetCurrencyCode });
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FinalizeUnits
|
||||
//
|
||||
// There are a few ways we can get the data needed for Currency Converter, including from cache or from web.
|
||||
// This function accepts the data from any source, and acts as a 'last-steps' for the converter to be ready.
|
||||
// This includes identifying which units will be selected and building the map of currency ratios.
|
||||
#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321
|
||||
task<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()));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue