Merge with upstream/master

This commit is contained in:
Rudy Huyn 2019-03-25 22:52:15 -07:00
commit b871f52c03
372 changed files with 3112 additions and 2149 deletions

View file

@ -5,7 +5,6 @@ root = true
[*] [*]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
end_of_line = crlf
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true

1
.gitignore vendored
View file

@ -290,4 +290,5 @@ __pycache__/
# Calculator specific # Calculator specific
Generated Files/ Generated Files/
!/build/config/TRexDefs/** !/build/config/TRexDefs/**
!src/Calculator/TemporaryKey.pfx
!src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx !src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx

View file

@ -15,30 +15,33 @@ name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
jobs: jobs:
- job: Localize - job: Localize
pool: pool:
name: Package ES Custom Demands Lab A vmImage: vs2017-win2016
demands: variables:
- ClientAlias -equals PKGESUTILAPPS skipComponentGovernanceDetection: true
workspace:
clean: outputs
steps: steps:
- checkout: self
clean: true
- task: PkgESSetupBuild@10 - task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@1
displayName: Initialize Package ES displayName: Send resources to Touchdown Build
inputs: inputs:
productName: Calculator teamId: 86
branchVersion: true authId: d3dd8113-65b3-4526-bdca-a00a7d1c37ba
authKey: $(LocServiceKey)
isPreview: false
relativePathRoot: src/Calculator/Resources/en-US/
resourceFilePath: '*.resw'
outputDirectoryRoot: src/Calculator/Resources/
- task: PkgESTouchdownLocService@10 - script: |
displayName: Package ES Touchdown Loc Service cd $(Build.SourcesDirectory)
git add -A
git diff --cached --exit-code
echo '##vso[task.setvariable variable=hasChanges]%errorlevel%'
git diff --cached > $(Build.ArtifactStagingDirectory)\LocalizedStrings.patch
displayName: Check for changes and create patch file
- task: PublishPipelineArtifact@0
displayName: Publish patch file as artifact
condition: eq(variables['hasChanges'], '1')
inputs: inputs:
IsCallToServiceStepSelected: true artifactName: Patch
IsCheckedInFileSelected: true targetPath: $(Build.ArtifactStagingDirectory)
CheckinFilesAtOriginFilePath: true
GitLocPath: Loc/Resources
LocConfigFile: build/config/LocConfigPackageEs.xml
AuthenticationMode: OAuth
ClientApplicationID: d3dd8113-65b3-4526-bdca-a00a7d1c37ba
ApplicationKeyID: $(LocServiceKey)
SendToLoc: true

View file

@ -9,8 +9,8 @@ pr: none
variables: variables:
versionMajor: 10 versionMajor: 10
versionMinor: 1902 versionMinor: 1903
versionBuild: $[counter('10.1902.*', 0)] versionBuild: $[counter('10.1903.*', 0)]
versionPatch: 0 versionPatch: 0
name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)' name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)'

View file

@ -29,7 +29,7 @@ jobs:
downloadDirectory: $(Build.SourcesDirectory) downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsApps vstsFeed: WindowsApps
vstsFeedPackage: calculator-internals vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.7 vstsPackageVersion: 0.0.10
- template: ./build-single-architecture.yaml - template: ./build-single-architecture.yaml
parameters: parameters:

View file

@ -87,7 +87,7 @@ jobs:
downloadDirectory: $(Build.SourcesDirectory) downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsApps vstsFeed: WindowsApps
vstsFeedPackage: calculator-internals vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.7 vstsPackageVersion: 0.0.10
- task: PkgESStoreBrokerPackage@10 - task: PkgESStoreBrokerPackage@10
displayName: Create StoreBroker Packages displayName: Create StoreBroker Packages

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Before After
Before After

View file

@ -9,6 +9,7 @@ In 2019, the Windows Calculator team is focused on:
* Iterating upon the existing app design based on the latest [Fluent Design guidelines](https://developer.microsoft.com/en-us/windows/apps/design) * Iterating upon the existing app design based on the latest [Fluent Design guidelines](https://developer.microsoft.com/en-us/windows/apps/design)
* Improving testing and diagnostics within the project * Improving testing and diagnostics within the project
* Investigating new features with a focus on addressing top user feedback, including: * Investigating new features with a focus on addressing top user feedback, including:
* Adding graphing mode
* Adding the ability for users to pin Calculator on top of other windows * Adding the ability for users to pin Calculator on top of other windows
* Providing additional customization options * Providing additional customization options
* [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started! * [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started!

View file

@ -1,10 +0,0 @@
root = true
[*.{xaml,cpp,h}]
charset = utf-8-bom
indent_style = space
indent_size = 4
[*.{cpp,h}]
insert_final_newline = true
trim_trailing_whitespace = true

View file

@ -3,6 +3,7 @@
#include "pch.h" #include "pch.h"
#include "Header Files/CalcEngine.h" #include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
bool IsOpInRange(WPARAM op, uint32_t x, uint32_t y) bool IsOpInRange(WPARAM op, uint32_t x, uint32_t y)
{ {

View file

@ -2,18 +2,25 @@
// Licensed under the MIT License. // Licensed under the MIT License.
#include "pch.h" #include "pch.h"
#pragma once
#include "Header Files/CalcEngine.h" #include "Header Files/CalcEngine.h"
#include "Command.h" #include "Command.h"
#include "CalculatorVector.h" #include "CalculatorVector.h"
#include "ExpressionCommand.h" #include "ExpressionCommand.h"
#include "CalcException.h"
constexpr int ASCII_0 = 48; constexpr int ASCII_0 = 48;
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;
namespace {
void IFT(HRESULT hr)
{
if (FAILED(hr))
{
throw hr;
}
}
}
void CHistoryCollector::ReinitHistory() void CHistoryCollector::ReinitHistory()
{ {
m_lastOpStartIndex = -1; m_lastOpStartIndex = -1;
@ -129,7 +136,7 @@ void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool fNoRepetition)
} }
// This is expected to be called when a binary op in the last say 1+2+ is changing to another one say 1+2* (+ changed to *) // This is expected to be called when a binary op in the last say 1+2+ is changing to another one say 1+2* (+ changed to *)
// It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new // It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new
// one isn't. (Eg. 1*2* to 1*2^). It can add explicit brackets to ensure the precedence is inverted. (Eg. (1*2) ^) // one isn't. (Eg. 1*2* to 1*2^). It can add explicit brackets to ensure the precedence is inverted. (Eg. (1*2) ^)
void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher) void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher)
{ {
@ -196,7 +203,7 @@ bool CHistoryCollector::FOpndAddedToHistory()
// AddUnaryOpToHistory // AddUnaryOpToHistory
// //
// This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt), // This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt),
// this routine will ensure the last sqrt call unary operator, actually goes back in history and wraps 4 in sqrt(4) // this routine will ensure the last sqrt call unary operator, actually goes back in history and wraps 4 in sqrt(4)
// //
void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype) void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype)
@ -290,7 +297,7 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a
} }
// Called after = with the result of the equation // Called after = with the result of the equation
// Responsible for clearing the top line of current running history display, as well as adding yet another element to // Responsible for clearing the top line of current running history display, as well as adding yet another element to
// history of equations // history of equations
void CHistoryCollector::CompleteHistoryLine(wstring_view numStr) void CHistoryCollector::CompleteHistoryLine(wstring_view numStr)
{ {
@ -406,37 +413,39 @@ int CHistoryCollector::AddCommand(_In_ const std::shared_ptr<IExpressionCommand>
return nCommands - 1; return nCommands - 1;
} }
//To Update the operands in the Expression according to the current Radix // To Update the operands in the Expression according to the current Radix
void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precision) void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precision)
{ {
if (m_spTokens != nullptr) if (m_spTokens == nullptr)
{ {
unsigned int size; return;
IFT(m_spTokens->GetSize(&size)); }
for (unsigned int i = 0; i < size; ++i) unsigned int size;
IFT(m_spTokens->GetSize(&size));
for (unsigned int i = 0; i < size; ++i)
{
std::pair<std::wstring, int> token;
IFT(m_spTokens->GetAt(i, &token));
int commandPosition = token.second;
if (commandPosition != -1)
{ {
std::pair<std::wstring, int> token; std::shared_ptr<IExpressionCommand> expCommand;
IFT(m_spTokens->GetAt(i, &token)); IFT(m_spCommands->GetAt(commandPosition, &expCommand));
int commandPosition = token.second; if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
if (commandPosition != -1)
{ {
std::shared_ptr<IExpressionCommand> expCommand; std::shared_ptr<COpndCommand> opndCommand = std::static_pointer_cast<COpndCommand>(expCommand);
IFT(m_spCommands->GetAt(commandPosition, &expCommand)); if (opndCommand != nullptr)
if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType())
{ {
std::shared_ptr<COpndCommand> opndCommand = std::static_pointer_cast<COpndCommand>(expCommand); token.first = opndCommand->GetString(radix, precision);
if (opndCommand != nullptr) IFT(m_spTokens->SetAt(i, token));
{ opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
token.first = opndCommand->GetString(radix, precision);
IFT(m_spTokens->SetAt(i, token));
opndCommand->SetCommands(GetOperandCommandsFromString(token.first));
}
} }
} }
} }
SetExpressionDisplay();
} }
SetExpressionDisplay();
} }
void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol) void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)
@ -444,7 +453,7 @@ void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)
m_decimalSymbol = decimalSymbol; m_decimalSymbol = decimalSymbol;
} }
//Update the commands corresponding to the passed string Number // Update the commands corresponding to the passed string Number
std::shared_ptr<CalculatorVector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) std::shared_ptr<CalculatorVector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr)
{ {
std::shared_ptr<CalculatorVector<int>> commands = std::make_shared<CalculatorVector<int>>(); std::shared_ptr<CalculatorVector<int>> commands = std::make_shared<CalculatorVector<int>>();

View file

@ -26,39 +26,41 @@
using namespace std; using namespace std;
using namespace CalcEngine; using namespace CalcEngine;
// NPrecedenceOfOp namespace {
// // NPrecedenceOfOp
// returns a virtual number for precedence for the operator. We expect binary operator only, otherwise the lowest number //
// 0 is returned. Higher the number, higher the precedence of the operator. // returns a virtual number for precedence for the operator. We expect binary operator only, otherwise the lowest number
INT NPrecedenceOfOp(int nopCode) // 0 is returned. Higher the number, higher the precedence of the operator.
{ INT NPrecedenceOfOp(int nopCode)
static BYTE rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1, {
IDC_ADD,2, IDC_SUB,2, IDC_RSHF,3, IDC_LSHF,3, static BYTE rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1,
IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 }; IDC_ADD,2, IDC_SUB,2, IDC_RSHF,3, IDC_LSHF,3,
int iPrec; IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 };
unsigned int iPrec;
iPrec = 0;
while ((iPrec < ARRAYSIZE(rgbPrec)) && (nopCode != rgbPrec[iPrec]))
{
iPrec += 2;
}
if (iPrec >= ARRAYSIZE(rgbPrec))
{
iPrec = 0; iPrec = 0;
} while ((iPrec < size(rgbPrec)) && (nopCode != rgbPrec[iPrec]))
return rgbPrec[iPrec + 1]; {
iPrec += 2;
}
if (iPrec >= size(rgbPrec))
{
iPrec = 0;
}
return rgbPrec[iPrec + 1];
}
} }
// HandleErrorCommand // HandleErrorCommand
// //
// When it is discovered by the state machine that at this point the input is not valid (eg. "1+)"), we want to proceed as though this input never // When it is discovered by the state machine that at this point the input is not valid (eg. "1+)"), we want to proceed as though this input never
// occurred and may be some feedback to user like Beep. The rest of input can then continue by just ignoring this command. // occurred and may be some feedback to user like Beep. The rest of input can then continue by just ignoring this command.
void CCalcEngine::HandleErrorCommand(WPARAM idc) void CCalcEngine::HandleErrorCommand(WPARAM idc)
{ {
if (!IsGuiSettingOpCode(idc)) if (!IsGuiSettingOpCode(idc))
{ {
// we would have saved the prev command. Need to forget this state // We would have saved the prev command. Need to forget this state
m_nTempCom = m_nLastCom; m_nTempCom = m_nLastCom;
} }
} }
@ -126,7 +128,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
} }
} }
// Toggle Record/Display mode if appropriate. // Toggle Record/Display mode if appropriate.
if (m_bRecord) if (m_bRecord)
{ {
if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) || if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) ||
@ -180,7 +182,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
// BINARY OPERATORS: // BINARY OPERATORS:
if (IsBinOpCode(wParam)) if (IsBinOpCode(wParam))
{ {
/* Change the operation if last input was operation. */ // Change the operation if last input was operation.
if (IsBinOpCode(m_nLastCom)) if (IsBinOpCode(m_nLastCom))
{ {
INT nPrev; INT nPrev;
@ -544,6 +546,11 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
if ((m_openParenCount >= MAXPRECDEPTH && nx) || (!m_openParenCount && !nx) if ((m_openParenCount >= MAXPRECDEPTH && nx) || (!m_openParenCount && !nx)
|| ((m_precedenceOpCount >= MAXPRECDEPTH && m_nPrecOp[m_precedenceOpCount - 1] != 0))) || ((m_precedenceOpCount >= MAXPRECDEPTH && m_nPrecOp[m_precedenceOpCount - 1] != 0)))
{ {
if (!m_openParenCount && !nx)
{
m_pCalcDisplay->OnNoRightParenAdded();
}
HandleErrorCommand(wParam); HandleErrorCommand(wParam);
break; break;
} }
@ -567,7 +574,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam)
m_lastVal = 0; m_lastVal = 0;
if (IsBinOpCode(m_nLastCom)) if (IsBinOpCode(m_nLastCom))
{ {
// We want 1 + ( to start as 1 + (0. Any number you type replaces 0. But if it is 1 + 3 (, it is // We want 1 + ( to start as 1 + (0. Any number you type replaces 0. But if it is 1 + 3 (, it is
// treated as 1 + (3 // treated as 1 + (3
m_currentVal = 0; m_currentVal = 0;
} }
@ -796,7 +803,7 @@ void CCalcEngine::CheckAndAddLastBinOpToHistory(bool addToHistory)
{ {
if (m_HistoryCollector.FOpndAddedToHistory()) if (m_HistoryCollector.FOpndAddedToHistory())
{ {
// if last time opnd was added but the last command was not a binary operator, then it must have come // if last time opnd was added but the last command was not a binary operator, then it must have come
// from commands which add the operand, like unary operator. So history at this is showing 1 + sqrt(4) // from commands which add the operand, like unary operator. So history at this is showing 1 + sqrt(4)
// but in reality the sqrt(4) is getting replaced by new number (may be unary op, or MR or SUM etc.) // but in reality the sqrt(4) is getting replaced by new number (may be unary op, or MR or SUM etc.)
// So erase the last operand // So erase the last operand
@ -848,7 +855,7 @@ void CCalcEngine::DisplayAnnounceBinaryOperator()
} }
// Unary operator Function Name table Element // Unary operator Function Name table Element
// since unary operators button names aren't exactly friendly for history purpose, // since unary operators button names aren't exactly friendly for history purpose,
// we have this separate table to get its localized name and for its Inv function if it exists. // we have this separate table to get its localized name and for its Inv function if it exists.
typedef struct typedef struct
{ {
@ -940,7 +947,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE
// Try to lookup the ID in the UFNE table // Try to lookup the ID in the UFNE table
int ids = 0; int ids = 0;
int iufne = nOpCode - IDC_UNARYFIRST; int iufne = nOpCode - IDC_UNARYFIRST;
if (iufne >= 0 && iufne < ARRAYSIZE(rgUfne)) if (iufne >= 0 && (size_t)iufne < size(rgUfne))
{ {
if (fInv) if (fInv)
{ {
@ -1020,7 +1027,7 @@ wstring CCalcEngine::GetCurrentResultForRadix(uint32_t radix, int32_t precision)
wstring numberString = GetStringForDisplay(rat, radix); wstring numberString = GetStringForDisplay(rat, radix);
if (!numberString.empty()) if (!numberString.empty())
{ {
//revert the precision to previously stored precision // Revert the precision to previously stored precision
ChangeConstants(m_radix, m_precision); ChangeConstants(m_radix, m_precision);
} }

View file

@ -70,7 +70,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
uint64_t w64Bits = result.ToUInt64_t(); uint64_t w64Bits = result.ToUInt64_t();
uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0; uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0;
w64Bits >>= 1; //RShift by 1 w64Bits >>= 1; // RShift by 1
w64Bits |= (lsb << (m_dwWordBitWidth - 1)); w64Bits |= (lsb << (m_dwWordBitWidth - 1));
result = w64Bits; result = w64Bits;

View file

@ -6,15 +6,16 @@
using namespace CalcEngine; using namespace CalcEngine;
using namespace CalcEngine::RationalMath; using namespace CalcEngine::RationalMath;
using namespace std;
// To be called when either the radix or num width changes. You can use -1 in either of these values to mean // To be called when either the radix or num width changes. You can use -1 in either of these values to mean
// dont change that. // dont change that.
void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth) void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth)
{ {
// When in integer mode, the number is represented in 2's complement form. When a bit width is changing, we can // When in integer mode, the number is represented in 2's complement form. When a bit width is changing, we can
// change the number representation back to sign, abs num form in ratpak. Soon when display sees this, it will // change the number representation back to sign, abs num form in ratpak. Soon when display sees this, it will
// convert to 2's complement form, but this time all high bits will be propagated. Eg. -127, in byte mode is // convert to 2's complement form, but this time all high bits will be propagated. Eg. -127, in byte mode is
// represented as 1000,0001. This puts it back as sign=-1, 01111111 . But DisplayNum will see this and convert it // represented as 1000,0001. This puts it back as sign=-1, 01111111 . But DisplayNum will see this and convert it
// back to 1111,1111,1000,0001 when in Word mode. // back to 1111,1111,1000,0001 when in Word mode.
if (m_fIntegerMode) if (m_fIntegerMode)
{ {
@ -45,7 +46,7 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwid
// inform ratpak that a change in base or precision has occurred // inform ratpak that a change in base or precision has occurred
BaseOrPrecisionChanged(); BaseOrPrecisionChanged();
// display the correct number for the new state (ie convert displayed // display the correct number for the new state (ie convert displayed
// number to correct base) // number to correct base)
DisplayNum(); DisplayNum();
} }
@ -55,7 +56,7 @@ LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
static constexpr int nBitMax[] = { 64, 32, 16, 8 }; static constexpr int nBitMax[] = { 64, 32, 16, 8 };
LONG wmax = nBitMax[0]; LONG wmax = nBitMax[0];
if (m_numwidth >= 0 && m_numwidth < ARRAYSIZE(nBitMax)) if (m_numwidth >= 0 && (size_t)m_numwidth < size(nBitMax))
{ {
wmax = nBitMax[m_numwidth]; wmax = nBitMax[m_numwidth];
} }
@ -68,7 +69,7 @@ uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype)
uint32_t radix = 10; uint32_t radix = 10;
// convert special bases into symbolic values // convert special bases into symbolic values
if (radixtype >= 0 && radixtype < ARRAYSIZE(rgnRadish)) if (radixtype >= 0 && (size_t)radixtype < size(rgnRadish))
{ {
radix = rgnRadish[radixtype]; radix = rgnRadish[radixtype];
} }
@ -142,7 +143,7 @@ void CCalcEngine::UpdateMaxIntDigits()
if (m_fIntegerMode) if (m_fIntegerMode)
{ {
m_cIntDigitsSav = static_cast<int>(m_maxDecimalValueStrings[m_numwidth].length()) - 1; m_cIntDigitsSav = static_cast<int>(m_maxDecimalValueStrings[m_numwidth].length()) - 1;
// This is the max digits you can enter a decimal in fixed width mode aka integer mode -1. The last digit // This is the max digits you can enter a decimal in fixed width mode aka integer mode -1. The last digit
// has to be checked separately // has to be checked separately
} }
else else
@ -160,10 +161,10 @@ void CCalcEngine::ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t
{ {
if (10 == radix) if (10 == radix)
{ {
ChangeConstants(radix, precision); // Base 10 precision for internal computing still needs to be 32, to ChangeConstants(radix, precision); // Base 10 precision for internal computing still needs to be 32, to
// take care of decimals precisely. For eg. to get the HI word of a qword, we do a rsh, which depends on getting // take care of decimals precisely. For eg. to get the HI word of a qword, we do a rsh, which depends on getting
// 18446744073709551615 / 4294967296 = 4294967295.9999917... This is important it works this and doesn't reduce // 18446744073709551615 / 4294967296 = 4294967295.9999917... This is important it works this and doesn't reduce
// the precision to number of digits allowed to enter. In other words, precision and # of allowed digits to be // the precision to number of digits allowed to enter. In other words, precision and # of allowed digits to be
// entered are different. // entered are different.
} }
else else

View file

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
class CalcException : public std::exception
{
public:
CalcException(HRESULT hr)
{
m_hr = hr;
}
HRESULT GetException()
{
return m_hr;
}
private:
HRESULT m_hr;
};
void IFT(HRESULT hr)
{
if (FAILED(hr))
{
CalcException exception(hr);
throw(exception);
}
}

View file

@ -119,7 +119,6 @@
<ClInclude Include="Ratpack\ratpak.h"> <ClInclude Include="Ratpack\ratpak.h">
<Filter>RatPack</Filter> <Filter>RatPack</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="CalcException.h" />
<ClInclude Include="CalculatorVector.h" /> <ClInclude Include="CalculatorVector.h" />
<ClInclude Include="Header Files\CalcEngine.h"> <ClInclude Include="Header Files\CalcEngine.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
@ -162,4 +161,4 @@
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -7,8 +7,7 @@
using namespace std; using namespace std;
using namespace CalculationManager; using namespace CalculationManager;
CalculatorHistory::CalculatorHistory(CALCULATOR_MODE eMode, size_t maxSize) : CalculatorHistory::CalculatorHistory(size_t maxSize) :
m_mode(eMode),
m_maxHistorySize(maxSize) m_maxHistorySize(maxSize)
{} {}
@ -23,7 +22,7 @@ unsigned int CalculatorHistory::AddToHistory(_In_ shared_ptr<CalculatorVector <p
// to be changed when pszexp is back // to be changed when pszexp is back
tokens->GetString(&generatedExpression); tokens->GetString(&generatedExpression);
// Prefixing and suffixing the special Unicode markers to ensure that the expression // Prefixing and suffixing the special Unicode markers to ensure that the expression
// in the history doesn't get broken for RTL languages // in the history doesn't get broken for RTL languages
spHistoryItem->historyItemVector.expression = L'\u202d' + generatedExpression + L'\u202c'; spHistoryItem->historyItemVector.expression = L'\u202d' + generatedExpression + L'\u202c';
spHistoryItem->historyItemVector.result = wstring(result); spHistoryItem->historyItemVector.result = wstring(result);
@ -35,15 +34,13 @@ unsigned int CalculatorHistory::AddToHistory(_In_ shared_ptr<CalculatorVector <p
unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const &spHistoryItem) unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const &spHistoryItem)
{ {
int lastIndex;
if (m_historyItems.size() >= m_maxHistorySize) if (m_historyItems.size() >= m_maxHistorySize)
{ {
m_historyItems.erase(m_historyItems.begin()); m_historyItems.erase(m_historyItems.begin());
} }
m_historyItems.push_back(spHistoryItem); m_historyItems.push_back(spHistoryItem);
lastIndex = static_cast<unsigned>(m_historyItems.size() - 1); unsigned int lastIndex = static_cast<unsigned>(m_historyItems.size() - 1);
return lastIndex; return lastIndex;
} }

View file

@ -31,7 +31,7 @@ namespace CalculationManager
{ {
public: public:
CalculatorHistory(CALCULATOR_MODE eMode, const size_t maxSize); CalculatorHistory(const size_t maxSize);
unsigned int AddToHistory(_In_ std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const &spTokens, _In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &spCommands, std::wstring_view result); unsigned int AddToHistory(_In_ std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const &spTokens, _In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &spCommands, std::wstring_view result);
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistory(); std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistory();
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(unsigned int uIdx); std::shared_ptr<HISTORYITEM> const& GetHistoryItem(unsigned int uIdx);
@ -43,7 +43,6 @@ namespace CalculationManager
private: private:
std::vector<std::shared_ptr<HISTORYITEM>> m_historyItems; std::vector<std::shared_ptr<HISTORYITEM>> m_historyItems;
CALCULATOR_MODE m_mode;
const size_t m_maxHistorySize; const size_t m_maxHistorySize;
}; };
} }

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "pch.h" #include "pch.h"
@ -24,15 +24,15 @@ namespace CalculationManager
{ {
CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider) : CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider) :
m_displayCallback(displayCallback), m_displayCallback(displayCallback),
m_currentCalculatorEngine(nullptr),
m_resourceProvider(resourceProvider), m_resourceProvider(resourceProvider),
m_inHistoryItemLoadMode(false),
m_persistedPrimaryValue(),
m_isExponentialFormat(false),
m_currentDegreeMode(Command::CommandNULL), m_currentDegreeMode(Command::CommandNULL),
m_savedDegreeMode(Command::CommandDEG), m_savedDegreeMode(Command::CommandDEG),
m_isExponentialFormat(false), m_pStdHistory(new CalculatorHistory(MAX_HISTORY_ITEMS)),
m_persistedPrimaryValue(), m_pSciHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
m_currentCalculatorEngine(nullptr),
m_pStdHistory(new CalculatorHistory(CM_STD, MAX_HISTORY_ITEMS)),
m_pSciHistory(new CalculatorHistory(CM_SCI, MAX_HISTORY_ITEMS)),
m_inHistoryItemLoadMode(false)
{ {
CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider); CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider);
} }
@ -109,7 +109,6 @@ namespace CalculationManager
/// <summary> /// <summary>
/// Callback from the engine /// Callback from the engine
/// Used to set the current unmatched open parenthesis count
/// </summary> /// </summary>
/// <param name="parenthesisCount">string containing the parenthesis count</param> /// <param name="parenthesisCount">string containing the parenthesis count</param>
void CalculatorManager::SetParenDisplayText(const wstring& parenthesisCount) void CalculatorManager::SetParenDisplayText(const wstring& parenthesisCount)
@ -117,6 +116,14 @@ namespace CalculationManager
m_displayCallback->SetParenDisplayText(parenthesisCount); m_displayCallback->SetParenDisplayText(parenthesisCount);
} }
/// <summary>
/// Callback from the engine
/// </summary>
void CalculatorManager::OnNoRightParenAdded()
{
m_displayCallback->OnNoRightParenAdded();
}
/// <summary> /// <summary>
/// Reset CalculatorManager. /// Reset CalculatorManager.
/// Set the mode to the standard calculator /// Set the mode to the standard calculator
@ -285,7 +292,7 @@ namespace CalculationManager
break; break;
case Command::CommandFE: case Command::CommandFE:
m_isExponentialFormat = !m_isExponentialFormat; m_isExponentialFormat = !m_isExponentialFormat;
// fall through [[fallthrough]];
default: default:
m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(command)); m_currentCalculatorEngine->ProcessCommand(static_cast<WPARAM>(command));
break; break;
@ -293,7 +300,7 @@ namespace CalculationManager
} }
/// <summary> /// <summary>
/// Convert Command to unsigned char. /// Convert Command to unsigned char.
/// Since some Commands are higher than 255, they are saved after subtracting 255 /// Since some Commands are higher than 255, they are saved after subtracting 255
/// The smallest Command is CommandSIGN = 80, thus, subtracted value does not overlap with other values. /// The smallest Command is CommandSIGN = 80, thus, subtracted value does not overlap with other values.
/// </summary> /// </summary>
@ -301,7 +308,10 @@ namespace CalculationManager
unsigned char CalculatorManager::MapCommandForSerialize(Command command) unsigned char CalculatorManager::MapCommandForSerialize(Command command)
{ {
unsigned int commandToSave = static_cast<unsigned int>(command); unsigned int commandToSave = static_cast<unsigned int>(command);
commandToSave > UCHAR_MAX ? commandToSave -= UCHAR_MAX : commandToSave; if (commandToSave > UCHAR_MAX)
{
commandToSave -= UCHAR_MAX;
}
return static_cast<unsigned char>(commandToSave); return static_cast<unsigned char>(commandToSave);
} }
@ -353,7 +363,7 @@ namespace CalculationManager
/// <param name = "serializedPrimaryDisplay">Serialized Rational of primary display</param> /// <param name = "serializedPrimaryDisplay">Serialized Rational of primary display</param>
void CalculatorManager::DeSerializePrimaryDisplay(const vector<long> &serializedPrimaryDisplay) void CalculatorManager::DeSerializePrimaryDisplay(const vector<long> &serializedPrimaryDisplay)
{ {
if (serializedPrimaryDisplay.size() == 0) if (serializedPrimaryDisplay.empty())
{ {
return; return;
} }
@ -428,9 +438,9 @@ namespace CalculationManager
if (*commandItr >= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber) && if (*commandItr >= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber) &&
*commandItr <= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizedNumberClearAll)) *commandItr <= MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizedNumberClearAll))
{ {
//MemoryCommands(which have values above 255) are pushed on m_savedCommands upon casting to unsigned char. // MemoryCommands(which have values above 255) are pushed on m_savedCommands upon casting to unsigned char.
//SerializeCommands uses m_savedCommands, which is then used in DeSerializeCommands. // SerializeCommands uses m_savedCommands, which is then used in DeSerializeCommands.
//Hence, a simple cast to MemoryCommand is not sufficient. // Hence, a simple cast to MemoryCommand is not sufficient.
MemoryCommand memoryCommand = static_cast<MemoryCommand>(*commandItr + UCHAR_MAX + 1); MemoryCommand memoryCommand = static_cast<MemoryCommand>(*commandItr + UCHAR_MAX + 1);
unsigned int indexOfMemory = 0; unsigned int indexOfMemory = 0;
switch (memoryCommand) switch (memoryCommand)
@ -483,22 +493,25 @@ namespace CalculationManager
void CalculatorManager::MemorizeNumber() void CalculatorManager::MemorizeNumber()
{ {
m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber)); m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber));
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
m_currentCalculatorEngine->ProcessCommand(IDC_STORE); return;
auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObjectPtr != nullptr)
{
m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr);
}
if (m_memorizedNumbers.size() > m_maximumMemorySize)
{
m_memorizedNumbers.resize(m_maximumMemorySize);
}
this->SetMemorizedNumbersString();
} }
m_currentCalculatorEngine->ProcessCommand(IDC_STORE);
auto memoryObjectPtr = m_currentCalculatorEngine->PersistedMemObject();
if (memoryObjectPtr != nullptr)
{
m_memorizedNumbers.insert(m_memorizedNumbers.begin(), *memoryObjectPtr);
}
if (m_memorizedNumbers.size() > m_maximumMemorySize)
{
m_memorizedNumbers.resize(m_maximumMemorySize);
}
this->SetMemorizedNumbersString();
} }
/// <summary> /// <summary>
@ -509,11 +522,14 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory)
{ {
SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory); SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
this->MemorizedNumberSelect(indexOfMemory); return;
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
} }
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_RECALL);
} }
/// <summary> /// <summary>
@ -525,24 +541,27 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory)
{ {
SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory); SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
if (m_memorizedNumbers.empty()) return;
{
this->MemorizeNumber();
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MPLUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
void CalculatorManager::MemorizedNumberClear(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberClear(_In_ unsigned int indexOfMemory)
@ -563,27 +582,30 @@ namespace CalculationManager
void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory)
{ {
SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory); SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory);
if (!(m_currentCalculatorEngine->FInErrorState()))
if (m_currentCalculatorEngine->FInErrorState())
{ {
// To add negative of the number on display to the memory -x = x - 2x return;
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
this->MemorizedNumberSubtract(0);
this->MemorizedNumberSubtract(0);
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
// To add negative of the number on display to the memory -x = x - 2x
if (m_memorizedNumbers.empty())
{
this->MemorizeNumber();
this->MemorizedNumberSubtract(0);
this->MemorizedNumberSubtract(0);
}
else
{
this->MemorizedNumberSelect(indexOfMemory);
m_currentCalculatorEngine->ProcessCommand(IDC_MMINUS);
this->MemorizedNumberChanged(indexOfMemory);
this->SetMemorizedNumbersString();
}
m_displayCallback->MemoryItemChanged(indexOfMemory);
} }
/// <summary> /// <summary>
@ -606,11 +628,13 @@ namespace CalculationManager
/// <param name="indexOfMemory">Index of the target memory</param> /// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberSelect(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberSelect(_In_ unsigned int indexOfMemory)
{ {
if (!(m_currentCalculatorEngine->FInErrorState())) if (m_currentCalculatorEngine->FInErrorState())
{ {
auto memoryObject = m_memorizedNumbers.at(indexOfMemory); return;
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
} }
auto memoryObject = m_memorizedNumbers.at(indexOfMemory);
m_currentCalculatorEngine->PersistedMemObject(memoryObject);
} }
/// <summary> /// <summary>
@ -620,13 +644,15 @@ namespace CalculationManager
/// <param name="indexOfMemory">Index of the target memory</param> /// <param name="indexOfMemory">Index of the target memory</param>
void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory) void CalculatorManager::MemorizedNumberChanged(_In_ unsigned int indexOfMemory)
{ {
if (!(m_currentCalculatorEngine->FInErrorState())) if (m_currentCalculatorEngine->FInErrorState())
{ {
auto memoryObject = m_currentCalculatorEngine->PersistedMemObject(); return;
if (memoryObject != nullptr) }
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject; auto memoryObject = m_currentCalculatorEngine->PersistedMemObject();
} if (memoryObject != nullptr)
{
m_memorizedNumbers.at(indexOfMemory) = *memoryObject;
} }
} }
@ -754,7 +780,7 @@ namespace CalculationManager
} }
void CalculatorManager::UpdateMaxIntDigits() void CalculatorManager::UpdateMaxIntDigits()
{ {
m_currentCalculatorEngine->UpdateMaxIntDigits(); m_currentCalculatorEngine->UpdateMaxIntDigits();
} }
@ -778,7 +804,7 @@ namespace CalculationManager
/// How Rational is serialized : /// How Rational is serialized :
/// Serialized Rational.P(Number) + Serialized Rational.Q(Number) /// Serialized Rational.P(Number) + Serialized Rational.Q(Number)
/// How Number is saved : /// How Number is saved :
/// [0] = Rational.P.Sign /// [0] = Rational.P.Sign
/// [1] = Rational.P.Mantissa.size /// [1] = Rational.P.Mantissa.size
/// [2] = Rational.P.Exp /// [2] = Rational.P.Exp
/// [3] = Rational.P.Mantissa[0] /// [3] = Rational.P.Mantissa[0]
@ -816,7 +842,7 @@ namespace CalculationManager
/// <summary> /// <summary>
/// Serialize Number to vector of long /// Serialize Number to vector of long
/// How Number is saved : /// How Number is saved :
/// [0] = Number.Sign /// [0] = Number.Sign
/// [1] = Number.Mantissa.size /// [1] = Number.Mantissa.size
/// [2] = Number.Exp /// [2] = Number.Exp
/// [3] = Number.Mantissa[0] /// [3] = Number.Mantissa[0]
@ -843,7 +869,7 @@ namespace CalculationManager
/// <summary> /// <summary>
/// DeserializeNumber vector and construct a Number /// DeserializeNumber vector and construct a Number
/// How Number is saved : /// How Number is saved :
/// [0] = Number.Sign /// [0] = Number.Sign
/// [1] = Number.Mantissa.size /// [1] = Number.Mantissa.size
/// [2] = Number.Exp /// [2] = Number.Exp
/// [3] = Number.Mantissa[0] /// [3] = Number.Mantissa[0]

View file

@ -27,9 +27,9 @@ namespace CalculationManager
ProgrammerModePrecision = 64 ProgrammerModePrecision = 64
}; };
// Numbering continues from the Enum Command from Command.h // Numbering continues from the Enum Command from Command.h
// with some gap to ensure there is no overlap of these ids // with some gap to ensure there is no overlap of these ids
// when static_cast<unsigned char> is performed on these ids // when static_cast<unsigned char> is performed on these ids
// they shouldn't fall in any number range greater than 80. So never // they shouldn't fall in any number range greater than 80. So never
// make the memory command ids go below 330 // make the memory command ids go below 330
enum class MemoryCommand enum class MemoryCommand
@ -42,7 +42,7 @@ namespace CalculationManager
MemorizedNumberClear = 335 MemorizedNumberClear = 335
}; };
class CalculatorManager sealed : public virtual ICalcDisplay class CalculatorManager final : public ICalcDisplay
{ {
private: private:
ICalcDisplay* const m_displayCallback; ICalcDisplay* const m_displayCallback;
@ -94,7 +94,8 @@ namespace CalculationManager
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 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 SetMemorizedNumbers(_In_ const std::vector<std::wstring>& memorizedNumbers) override;
void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override;
void SetParenDisplayText(const std::wstring& parenthesisCount); void SetParenDisplayText(const std::wstring& parenthesisCount) override;
void OnNoRightParenAdded() override;
void DisplayPasteError(); void DisplayPasteError();
void MaxDigitsReached() override; void MaxDigitsReached() override;
void BinaryOperatorReceived() override; void BinaryOperatorReceived() override;
@ -140,7 +141,7 @@ namespace CalculationManager
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(_In_ unsigned int uIdx); std::shared_ptr<HISTORYITEM> const& GetHistoryItem(_In_ unsigned int uIdx);
bool RemoveHistoryItem(_In_ unsigned int uIdx); bool RemoveHistoryItem(_In_ unsigned int uIdx);
void ClearHistory(); void ClearHistory();
const size_t MaxHistorySize() const { return m_pHistory->MaxHistorySize(); } size_t MaxHistorySize() const { return m_pHistory->MaxHistorySize(); }
CalculationManager::Command GetCurrentDegreeMode(); CalculationManager::Command GetCurrentDegreeMode();
void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector<std::shared_ptr<HISTORYITEM>> const& history); void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector<std::shared_ptr<HISTORYITEM>> const& history);
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode); void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);

View file

@ -10,7 +10,7 @@ namespace CalculationManager
public: public:
virtual ~IResourceProvider() { } virtual ~IResourceProvider() { }
// Should return a string from the resource table for strings used // Should return a string from the resource table for strings used
// by the calculation engine. The strings that must be defined // by the calculation engine. The strings that must be defined
// and the ids to define them with can be seen in EngineStrings.h // and the ids to define them with can be seen in EngineStrings.h
// with SIDS prefix. Additionally it must provide values for string // with SIDS prefix. Additionally it must provide values for string

View file

@ -4,7 +4,7 @@
#pragma once #pragma once
template <typename TType> template <typename TType>
class CalculatorVector class CalculatorVector
{ {
public: public:
HRESULT GetAt(_In_opt_ unsigned int index, _Out_ TType *item) HRESULT GetAt(_In_opt_ unsigned int index, _Out_ TType *item)

View file

@ -94,7 +94,7 @@ namespace CalculationManager
CommandFAC = 113, CommandFAC = 113,
CommandREC = 114, CommandREC = 114,
CommandDMS = 115, CommandDMS = 115,
CommandCUBEROOT = 116, //x ^ 1/3 CommandCUBEROOT = 116, // x ^ 1/3
CommandPOW10 = 117, // 10 ^ x CommandPOW10 = 117, // 10 ^ x
CommandPERCENT = 118, CommandPERCENT = 118,

View file

@ -75,19 +75,19 @@ void CUnaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
CBinaryCommand::CBinaryCommand(int command) :m_command(command) CBinaryCommand::CBinaryCommand(int command) :m_command(command)
{} {}
void CBinaryCommand::SetCommand(int command) void CBinaryCommand::SetCommand(int command)
{ {
m_command = command; m_command = command;
} }
int CBinaryCommand::GetCommand() const int CBinaryCommand::GetCommand() const
{ {
return m_command; return m_command;
} }
CalculationManager::CommandType CBinaryCommand::GetCommandType() const CalculationManager::CommandType CBinaryCommand::GetCommandType() const
{ {
return CalculationManager::CommandType::BinaryCommand; return CalculationManager::CommandType::BinaryCommand;
} }
void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor) void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
@ -98,8 +98,8 @@ void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor)
COpndCommand::COpndCommand(shared_ptr<CalculatorVector<int>> const &commands, bool fNegative, bool fDecimal, bool fSciFmt) : COpndCommand::COpndCommand(shared_ptr<CalculatorVector<int>> const &commands, bool fNegative, bool fDecimal, bool fSciFmt) :
m_commands(commands), m_commands(commands),
m_fNegative(fNegative), m_fNegative(fNegative),
m_fDecimal(fDecimal),
m_fSciFmt(fSciFmt), m_fSciFmt(fSciFmt),
m_fDecimal(fDecimal),
m_fInitialized(false), m_fInitialized(false),
m_value{} m_value{}
{} {}
@ -111,8 +111,8 @@ void COpndCommand::Initialize(Rational const& rat)
} }
const shared_ptr<CalculatorVector<int>> & COpndCommand::GetCommands() const const shared_ptr<CalculatorVector<int>> & COpndCommand::GetCommands() const
{ {
return m_commands; return m_commands;
} }
void COpndCommand::SetCommands(shared_ptr<CalculatorVector<int>> const& commands) void COpndCommand::SetCommands(shared_ptr<CalculatorVector<int>> const& commands)
@ -166,7 +166,7 @@ void COpndCommand::RemoveFromEnd()
{ {
unsigned int nCommands; unsigned int nCommands;
m_commands->GetSize(&nCommands); m_commands->GetSize(&nCommands);
if (nCommands == 1) if (nCommands == 1)
{ {
ClearAllAndAppendCommand(CalculationManager::Command::Command0); ClearAllAndAppendCommand(CalculationManager::Command::Command0);
@ -185,8 +185,8 @@ void COpndCommand::RemoveFromEnd()
} }
bool COpndCommand::IsNegative() const bool COpndCommand::IsNegative() const
{ {
return m_fNegative; return m_fNegative;
} }
bool COpndCommand::IsSciFmt() const bool COpndCommand::IsSciFmt() const
@ -195,13 +195,13 @@ bool COpndCommand::IsSciFmt() const
} }
bool COpndCommand::IsDecimalPresent() const bool COpndCommand::IsDecimalPresent() const
{ {
return m_fDecimal; return m_fDecimal;
} }
CalculationManager::CommandType COpndCommand::GetCommandType() const CalculationManager::CommandType COpndCommand::GetCommandType() const
{ {
return CalculationManager::CommandType::OperandCommand; return CalculationManager::CommandType::OperandCommand;
} }
void COpndCommand::ClearAllAndAppendCommand(CalculationManager::Command command) void COpndCommand::ClearAllAndAppendCommand(CalculationManager::Command command)
@ -283,7 +283,7 @@ const wstring & COpndCommand::GetToken(wchar_t decimalSymbol)
m_token.clear(); m_token.clear();
m_token.append(&chZero); m_token.append(&chZero);
} }
return m_token; return m_token;
} }

View file

@ -45,7 +45,7 @@
// Key IDs: // Key IDs:
// These id's must be consecutive from IDC_FIRSTCONTROL to IDC_LASTCONTROL. // These id's must be consecutive from IDC_FIRSTCONTROL to IDC_LASTCONTROL.
// The actual values don't matter but the order and sequence are very important. // The actual values don't matter but the order and sequence are very important.
// Also, the order of the controls must match the order of the control names // Also, the order of the controls must match the order of the control names
// in the string table. // in the string table.
@ -97,7 +97,7 @@
#define IDC_FAC 113 #define IDC_FAC 113
#define IDC_REC 114 #define IDC_REC 114
#define IDC_DMS 115 #define IDC_DMS 115
#define IDC_CUBEROOT 116 //x ^ 1/3 #define IDC_CUBEROOT 116 // x ^ 1/3
#define IDC_POW10 117 // 10 ^ x #define IDC_POW10 117 // 10 ^ x
#define IDC_PERCENT 118 #define IDC_PERCENT 118
#define IDC_UNARYLAST IDC_PERCENT #define IDC_UNARYLAST IDC_PERCENT

View file

@ -85,7 +85,7 @@ private:
// if it hasn't yet been computed // if it hasn't yet been computed
bool m_bChangeOp; /* Flag for changing operation. */ bool m_bChangeOp; /* Flag for changing operation. */
bool m_bRecord; // Global mode: recording or displaying bool m_bRecord; // Global mode: recording or displaying
bool m_bSetCalcState; //Flag for setting the engine result state bool m_bSetCalcState; // Flag for setting the engine result state
CalcEngine::CalcInput m_input; // Global calc input object for decimal strings CalcEngine::CalcInput m_input; // Global calc input object for decimal strings
eNUMOBJ_FMT m_nFE; /* Scientific notation conversion flag. */ eNUMOBJ_FMT m_nFE; /* Scientific notation conversion flag. */
CalcEngine::Rational m_maxTrigonometricNum; CalcEngine::Rational m_maxTrigonometricNum;

View file

@ -6,7 +6,7 @@
#include "Rational.h" #include "Rational.h"
// Space to hold enough digits for a quadword binary number (64) plus digit separator strings for that number (20) // Space to hold enough digits for a quadword binary number (64) plus digit separator strings for that number (20)
constexpr int MAX_STRLEN = 84; constexpr int MAX_STRLEN = 84;
namespace CalcEngine namespace CalcEngine
{ {

View file

@ -128,7 +128,7 @@
#define SIDS_NFACTORIAL L"33" #define SIDS_NFACTORIAL L"33"
#define SIDS_RECIPROCAL L"34" #define SIDS_RECIPROCAL L"34"
#define SIDS_DMS L"35" #define SIDS_DMS L"35"
#define SIDS_CUBEROOT L"36" #define SIDS_CUBEROOT L"36"
#define SIDS_POWTEN L"37" #define SIDS_POWTEN L"37"
#define SIDS_PERCENT L"38" #define SIDS_PERCENT L"38"
#define SIDS_SCIENTIFIC_NOTATION L"39" #define SIDS_SCIENTIFIC_NOTATION L"39"
@ -200,7 +200,7 @@
#define SIDS_NOMEM L"105" #define SIDS_NOMEM L"105"
#define SIDS_TOOMANY L"106" #define SIDS_TOOMANY L"106"
#define SIDS_OVERFLOW L"107" #define SIDS_OVERFLOW L"107"
#define SIDS_NORESULT L"108" #define SIDS_NORESULT L"108"
#define SIDS_INSUFFICIENT_DATA L"109" #define SIDS_INSUFFICIENT_DATA L"109"
// 110 is skipped by CSTRINGSENGMAX // 110 is skipped by CSTRINGSENGMAX
#define SIDS_ERR_UNK_CH L"111" #define SIDS_ERR_UNK_CH L"111"
@ -214,7 +214,7 @@
#define SIDS_ERR_INPUT_OVERFLOW L"119" #define SIDS_ERR_INPUT_OVERFLOW L"119"
#define SIDS_ERR_OUTPUT_OVERFLOW L"120" #define SIDS_ERR_OUTPUT_OVERFLOW L"120"
__declspec(selectany) std::wstring g_sids[] = __declspec(selectany) std::wstring g_sids[] =
{ {
std::wstring(SIDS_PLUS_MINUS), std::wstring(SIDS_PLUS_MINUS),
std::wstring(SIDS_C), std::wstring(SIDS_C),
@ -252,7 +252,7 @@ __declspec(selectany) std::wstring g_sids[] =
std::wstring(SIDS_NFACTORIAL), std::wstring(SIDS_NFACTORIAL),
std::wstring(SIDS_RECIPROCAL), std::wstring(SIDS_RECIPROCAL),
std::wstring(SIDS_DMS), std::wstring(SIDS_DMS),
std::wstring(SIDS_CUBEROOT), std::wstring(SIDS_CUBEROOT),
std::wstring(SIDS_POWTEN), std::wstring(SIDS_POWTEN),
std::wstring(SIDS_PERCENT), std::wstring(SIDS_PERCENT),
std::wstring(SIDS_SCIENTIFIC_NOTATION), std::wstring(SIDS_SCIENTIFIC_NOTATION),
@ -324,7 +324,7 @@ __declspec(selectany) std::wstring g_sids[] =
std::wstring(SIDS_NOMEM), std::wstring(SIDS_NOMEM),
std::wstring(SIDS_TOOMANY), std::wstring(SIDS_TOOMANY),
std::wstring(SIDS_OVERFLOW), std::wstring(SIDS_OVERFLOW),
std::wstring(SIDS_NORESULT), std::wstring(SIDS_NORESULT),
std::wstring(SIDS_INSUFFICIENT_DATA), std::wstring(SIDS_INSUFFICIENT_DATA),
std::wstring(SIDS_ERR_UNK_CH), std::wstring(SIDS_ERR_UNK_CH),
std::wstring(SIDS_ERR_UNK_FN), std::wstring(SIDS_ERR_UNK_FN),

View file

@ -10,8 +10,8 @@
// maximum depth you can get by precedence. It is just an array's size limit. // maximum depth you can get by precedence. It is just an array's size limit.
static constexpr size_t MAXPRECDEPTH = 25; static constexpr size_t MAXPRECDEPTH = 25;
// Helper class really a internal class to CCalcEngine, to accumulate each history line of text by collecting the // Helper class really a internal class to CCalcEngine, to accumulate each history line of text by collecting the
// operands, operator, unary operator etc. Since it is a separate entity, it can be unit tested on its own but does // operands, operator, unary operator etc. Since it is a separate entity, it can be unit tested on its own but does
// rely on CCalcEngine calling it in appropriate order. // rely on CCalcEngine calling it in appropriate order.
class CHistoryCollector { class CHistoryCollector {
public: public:
@ -39,13 +39,13 @@ private:
ICalcDisplay *m_pCalcDisplay; ICalcDisplay *m_pCalcDisplay;
int m_iCurLineHistStart; // index of the beginning of the current equation int m_iCurLineHistStart; // index of the beginning of the current equation
// a sort of state, set to the index before 2 after 2 in the expression 2 + 3 say. Useful for auto correct portion of history and for // a sort of state, set to the index before 2 after 2 in the expression 2 + 3 say. Useful for auto correct portion of history and for
// attaching the unary op around the last operand // attaching the unary op around the last operand
int m_lastOpStartIndex; // index of the beginning of the last operand added to the history int m_lastOpStartIndex; // index of the beginning of the last operand added to the history
int m_lastBinOpStartIndex; // index of the beginning of the last binary operator added to the history int m_lastBinOpStartIndex; // index of the beginning of the last binary operator added to the history
std::array<int, MAXPRECDEPTH> m_operandIndices; // Stack of index of opnd's beginning for each '('. A parallel array to m_hnoParNum, but abstracted independently of that std::array<int, MAXPRECDEPTH> m_operandIndices; // Stack of index of opnd's beginning for each '('. A parallel array to m_hnoParNum, but abstracted independently of that
int m_curOperandIndex; // Stack index for the above stack int m_curOperandIndex; // Stack index for the above stack
bool m_bLastOpndBrace; // iff the last opnd in history is already braced so we can avoid putting another one for unary operator bool m_bLastOpndBrace; // iff the last opnd in history is already braced so we can avoid putting another one for unary operator
wchar_t m_decimalSymbol; wchar_t m_decimalSymbol;
std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> m_spTokens; std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> m_spTokens;
std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> m_spCommands; std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> m_spCommands;

View file

@ -13,6 +13,7 @@ public:
virtual void SetIsInError(bool isInError) = 0; virtual void SetIsInError(bool isInError) = 0;
virtual 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) = 0; virtual 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) = 0;
virtual void SetParenDisplayText(const std::wstring& pszText) = 0; virtual void SetParenDisplayText(const std::wstring& pszText) = 0;
virtual void OnNoRightParenAdded() = 0;
virtual void MaxDigitsReached() = 0; // not an error but still need to inform UI layer. virtual void MaxDigitsReached() = 0; // not an error but still need to inform UI layer.
virtual void BinaryOperatorReceived() = 0; virtual void BinaryOperatorReceived() = 0;
virtual void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) = 0; virtual void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) = 0;

View file

@ -2,17 +2,17 @@
// Licensed under the MIT License. // Licensed under the MIT License.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Package Title ratpak // Package Title ratpak
// File basex.c // File basex.c
// Copyright (C) 1995-97 Microsoft // Copyright (C) 1995-97 Microsoft
// Date 03-14-97 // Date 03-14-97
// //
// //
// Description // Description
// //
// Contains number routines for internal base computations, these assume // Contains number routines for internal base computations, these assume
// internal base is a power of 2. // internal base is a power of 2.
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "pch.h" #include "pch.h"
#include "ratpak.h" #include "ratpak.h"
@ -41,7 +41,7 @@ void __inline mulnumx( PNUMBER *pa, PNUMBER b )
{ {
// If b is not one we multiply // If b is not one we multiply
if ( (*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0 ) if ( (*pa)->cdigit > 1 || (*pa)->mant[0] != 1 || (*pa)->exp != 0 )
{ {
// pa and b are both non-one. // pa and b are both non-one.
_mulnumx( pa, b ); _mulnumx( pa, b );
} }
@ -91,7 +91,7 @@ void _mulnumx( PNUMBER *pa, PNUMBER b )
MANTTYPE da=0; // da is the digit from the fist number. MANTTYPE da=0; // da is the digit from the fist number.
TWO_MANTTYPE cy=0; // cy is the carry resulting from the addition of TWO_MANTTYPE cy=0; // cy is the carry resulting from the addition of
// a multiplied row into the result. // a multiplied row into the result.
TWO_MANTTYPE mcy=0; // mcy is the resultant from a single TWO_MANTTYPE mcy=0; // mcy is the resultant from a single
// multiply, AND the carry of that multiply. // multiply, AND the carry of that multiply.
long icdigit=0; // Index of digit being calculated in final result. long icdigit=0; // Index of digit being calculated in final result.
@ -110,8 +110,8 @@ void _mulnumx( PNUMBER *pa, PNUMBER b )
{ {
da = *ptra++; da = *ptra++;
ptrb = b->mant; ptrb = b->mant;
// Shift ptrc, and ptrcoffset, one for each digit // Shift ptrc, and ptrcoffset, one for each digit
ptrc = ptrcoffset++; ptrc = ptrcoffset++;
for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- ) for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- )
@ -126,28 +126,28 @@ void _mulnumx( PNUMBER *pa, PNUMBER b )
c->cdigit++; c->cdigit++;
} }
} }
// If result is nonzero, or while result of carry is nonzero... // If result is nonzero, or while result of carry is nonzero...
while ( mcy || cy ) while ( mcy || cy )
{ {
// update carry from addition(s) and multiply. // update carry from addition(s) and multiply.
cy += (TWO_MANTTYPE)ptrc[icdigit]+((DWORD)mcy&((DWORD)~BASEX)); cy += (TWO_MANTTYPE)ptrc[icdigit]+((DWORD)mcy&((DWORD)~BASEX));
// update result digit from // update result digit from
ptrc[icdigit++]=(MANTTYPE)((DWORD)cy&((DWORD)~BASEX)); ptrc[icdigit++]=(MANTTYPE)((DWORD)cy&((DWORD)~BASEX));
// update carries from // update carries from
mcy >>= BASEXPWR; mcy >>= BASEXPWR;
cy >>= BASEXPWR; cy >>= BASEXPWR;
} }
ptrb++; ptrb++;
ptrc++; ptrc++;
} }
} }
// prevent different kinds of zeros, by stripping leading duplicate zeros. // prevent different kinds of zeros, by stripping leading duplicate zeros.
// digits are in order of increasing significance. // digits are in order of increasing significance.
while ( c->cdigit > 1 && c->mant[c->cdigit-1] == 0 ) while ( c->cdigit > 1 && c->mant[c->cdigit-1] == 0 )
@ -198,7 +198,7 @@ void numpowlongx( _Inout_ PNUMBER *proot, _In_ long power )
} }
destroynum( *proot ); destroynum( *proot );
*proot=lret; *proot=lret;
} }
void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision); void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision);
@ -275,14 +275,14 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
a=*pa; a=*pa;
if ( thismax < a->cdigit ) if ( thismax < a->cdigit )
{ {
// a has more digits than precision specified, bump up digits to shoot // a has more digits than precision specified, bump up digits to shoot
// for. // for.
thismax = a->cdigit; thismax = a->cdigit;
} }
if ( thismax < b->cdigit ) if ( thismax < b->cdigit )
{ {
// b has more digits than precision specified, bump up digits to shoot // b has more digits than precision specified, bump up digits to shoot
// for. // for.
thismax = b->cdigit; thismax = b->cdigit;
} }
@ -317,7 +317,7 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
digit *= 2; digit *= 2;
} }
if ( lessnum( rem, tmp ) ) if ( lessnum( rem, tmp ) )
{ {
// too far, back up... // too far, back up...
destroynum( tmp ); destroynum( tmp );
digit /= 2; digit /= 2;
@ -326,7 +326,7 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
} }
tmp->sign *= -1; tmp->sign *= -1;
addnum( &rem, tmp, BASEX ); addnum( &rem, tmp, BASEX );
destroynum( tmp ); destroynum( tmp );
destroynum( lasttmp ); destroynum( lasttmp );
*ptrc |= digit; *ptrc |= digit;
@ -341,7 +341,7 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
} }
if ( !cdigits ) if ( !cdigits )
{ {
// A zero, make sure no weird exponents creep in // A zero, make sure no weird exponents creep in
c->exp = 0; c->exp = 0;
c->cdigit = 1; c->cdigit = 1;
@ -350,7 +350,7 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision)
{ {
c->cdigit = cdigits; c->cdigit = cdigits;
c->exp -= cdigits; c->exp -= cdigits;
// prevent different kinds of zeros, by stripping leading duplicate // prevent different kinds of zeros, by stripping leading duplicate
// zeros. digits are in order of increasing significance. // zeros. digits are in order of increasing significance.
while ( c->cdigit > 1 && c->mant[c->cdigit-1] == 0 ) while ( c->cdigit > 1 && c->mant[c->cdigit-1] == 0 )
{ {

View file

@ -61,7 +61,7 @@ void* zmalloc(size_t a)
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void _dupnum(_In_ PNUMBER dest, _In_ PNUMBER src) void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER * const src)
{ {
memcpy(dest, src, (int)(sizeof(NUMBER) + ((src)->cdigit)*(sizeof(MANTTYPE)))); memcpy(dest, src, (int)(sizeof(NUMBER) + ((src)->cdigit)*(sizeof(MANTTYPE))));
} }
@ -612,6 +612,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis
break; break;
} }
// Drop through in the 'e'-as-a-digit case // Drop through in the 'e'-as-a-digit case
[[fallthrough]];
default: default:
state = machine[state][NZ]; state = machine[state][NZ];
break; break;
@ -646,7 +647,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis
break; break;
case LD: case LD:
pnumret->exp++; pnumret->exp++;
// Fall through [[fallthrough]];
case DD: case DD:
{ {
curChar = NormalizeCharDigit(curChar, radix); curChar = NormalizeCharDigit(curChar, radix);
@ -801,7 +802,7 @@ PNUMBER longtonum( long inlong, uint32_t radix)
// RETURN: number // RETURN: number
// //
// DESCRIPTION: Returns a number representation in the // DESCRIPTION: Returns a number representation in the
// base requested of the unsigned long value passed in. Being unsigned number it has no // base requested of the unsigned long value passed in. Being unsigned number it has no
// negative number and takes the full range of unsigned number // negative number and takes the full range of unsigned number
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -817,7 +818,7 @@ PNUMBER Ulongtonum(unsigned long inlong, uint32_t radix)
pnumret->cdigit = 0; pnumret->cdigit = 0;
pnumret->exp = 0; pnumret->exp = 0;
pnumret->sign = 1; pnumret->sign = 1;
do { do {
*pmant++ = (MANTTYPE)(inlong % radix); *pmant++ = (MANTTYPE)(inlong % radix);
inlong /= radix; inlong /= radix;
@ -1270,7 +1271,7 @@ PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision)
// Convert p and q of rational form from internal base to requested base. // Convert p and q of rational form from internal base to requested base.
// Scale by largest power of BASEX possible. // Scale by largest power of BASEX possible.
long scaleby = min(temprat->pp->exp, temprat->pq->exp); long scaleby = min(temprat->pp->exp, temprat->pq->exp);
scaleby = max(scaleby, 0); scaleby = max(scaleby, 0l);
temprat->pp->exp -= scaleby; temprat->pp->exp -= scaleby;
temprat->pq->exp -= scaleby; temprat->pq->exp -= scaleby;

View file

@ -46,8 +46,8 @@ void _exprat( PRAT *px, int32_t precision)
{ {
CREATETAYLOR(); CREATETAYLOR();
addnum(&(pret->pp),num_one, BASEX); addnum(&(pret->pp),num_one, BASEX);
addnum(&(pret->pq),num_one, BASEX); addnum(&(pret->pq),num_one, BASEX);
DUPRAT(thisterm,pret); DUPRAT(thisterm,pret);
n2=longtonum(0L, BASEX); n2=longtonum(0L, BASEX);
@ -81,7 +81,7 @@ void exprat( PRAT *px, uint32_t radix, int32_t precision)
ratpowlong( &pwr, intpwr, precision); ratpowlong( &pwr, intpwr, precision);
subrat(px, pint, precision); subrat(px, pint, precision);
// It just so happens to be an integral power of e. // It just so happens to be an integral power of e.
if ( rat_gt( *px, rat_negsmallest, precision) && rat_lt( *px, rat_smallest, precision) ) if ( rat_gt( *px, rat_negsmallest, precision) && rat_lt( *px, rat_smallest, precision) )
{ {
@ -131,7 +131,7 @@ void _lograt( PRAT *px, int32_t precision)
CREATETAYLOR(); CREATETAYLOR();
createrat(thisterm); createrat(thisterm);
// sub one from x // sub one from x
(*px)->pq->sign *= -1; (*px)->pq->sign *= -1;
addnum(&((*px)->pp),(*px)->pq, BASEX); addnum(&((*px)->pp),(*px)->pq, BASEX);
@ -158,14 +158,14 @@ void lograt( PRAT *px, int32_t precision)
bool fneglog; bool fneglog;
PRAT pwr = nullptr; // pwr is the large scaling factor. PRAT pwr = nullptr; // pwr is the large scaling factor.
PRAT offset = nullptr; // offset is the incremental scaling factor. PRAT offset = nullptr; // offset is the incremental scaling factor.
// Check for someone taking the log of zero or a negative number. // Check for someone taking the log of zero or a negative number.
if ( rat_le( *px, rat_zero, precision) ) if ( rat_le( *px, rat_zero, precision) )
{ {
throw( CALC_E_DOMAIN ); throw( CALC_E_DOMAIN );
} }
// Get number > 1, for scaling // Get number > 1, for scaling
fneglog = rat_lt( *px, rat_one, precision); fneglog = rat_lt( *px, rat_one, precision);
if ( fneglog ) if ( fneglog )
@ -176,12 +176,12 @@ void lograt( PRAT *px, int32_t precision)
(*px)->pp = (*px)->pq; (*px)->pp = (*px)->pq;
(*px)->pq = pnumtemp; (*px)->pq = pnumtemp;
} }
// Scale the number within BASEX factor of 1, for the large scale. // Scale the number within BASEX factor of 1, for the large scale.
// log(x*2^(BASEXPWR*k)) = BASEXPWR*k*log(2)+log(x) // log(x*2^(BASEXPWR*k)) = BASEXPWR*k*log(2)+log(x)
if ( LOGRAT2(*px) > 1 ) if ( LOGRAT2(*px) > 1 )
{ {
// Take advantage of px's base BASEX to scale quickly down to // Take advantage of px's base BASEX to scale quickly down to
// a reasonable range. // a reasonable range.
long intpwr; long intpwr;
intpwr=LOGRAT2(*px)-1; intpwr=LOGRAT2(*px)-1;
@ -206,17 +206,17 @@ void lograt( PRAT *px, int32_t precision)
} }
_lograt(px, precision); _lograt(px, precision);
// Add the large and small scaling factors, take into account // Add the large and small scaling factors, take into account
// small scaling was done in e_to_one_half chunks. // small scaling was done in e_to_one_half chunks.
divrat(&offset, rat_two, precision); divrat(&offset, rat_two, precision);
addrat(&pwr, offset, precision); addrat(&pwr, offset, precision);
// And add the resulting scaling factor to the answer. // And add the resulting scaling factor to the answer.
addrat(px, pwr, precision); addrat(px, pwr, precision);
trimit(px, precision); trimit(px, precision);
// If number started out < 1 rescale answer to negative. // If number started out < 1 rescale answer to negative.
if ( fneglog ) if ( fneglog )
{ {
@ -224,9 +224,9 @@ void lograt( PRAT *px, int32_t precision)
} }
destroyrat(offset); destroyrat(offset);
destroyrat(pwr); destroyrat(pwr);
} }
void log10rat( PRAT *px, int32_t precision) void log10rat( PRAT *px, int32_t precision)
{ {
@ -235,7 +235,7 @@ void log10rat( PRAT *px, int32_t precision)
} }
// //
// return if the given x is even number. The assumption here is its denominator is 1 and we are testing the numerator is // return if the given x is even number. The assumption here is its denominator is 1 and we are testing the numerator is
// even or not // even or not
bool IsEven(PRAT x, uint32_t radix, int32_t precision) bool IsEven(PRAT x, uint32_t radix, int32_t precision)
{ {
@ -318,7 +318,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
// 1. Initialize result. // 1. Initialize result.
PRAT pxPow = nullptr; PRAT pxPow = nullptr;
DUPRAT(pxPow, *px); DUPRAT(pxPow, *px);
// 2. Calculate pxPow = px ^ yNumerator // 2. Calculate pxPow = px ^ yNumerator
// if yNumerator is not 1 // if yNumerator is not 1
if (!rat_equ(yNumerator, rat_one, precision)) if (!rat_equ(yNumerator, rat_one, precision))
@ -341,7 +341,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
PRAT originalResult = nullptr; PRAT originalResult = nullptr;
DUPRAT(originalResult, pxPow); DUPRAT(originalResult, pxPow);
powratcomp(&originalResult, oneoveryDenom, radix, precision); powratcomp(&originalResult, oneoveryDenom, radix, precision);
// ################################## // ##################################
// Round the originalResult to roundedResult // Round the originalResult to roundedResult
// ################################## // ##################################
@ -375,7 +375,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis
else else
{ {
DUPRAT(*px, originalResult); DUPRAT(*px, originalResult);
} }
destroyrat(oneoveryDenom); destroyrat(oneoveryDenom);
destroyrat(originalResult); destroyrat(originalResult);
@ -429,7 +429,7 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
sign = 1; sign = 1;
} }
} }
else else
{ {
PRAT pxint= nullptr; PRAT pxint= nullptr;
DUPRAT(pxint,*px); DUPRAT(pxint,*px);
@ -491,7 +491,7 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
PRAT pNumerator = nullptr; PRAT pNumerator = nullptr;
PRAT pDenominator = nullptr; PRAT pDenominator = nullptr;
bool fBadExponent = false; bool fBadExponent = false;
// Get the numbers in arbitrary precision rational number format // Get the numbers in arbitrary precision rational number format
DUPRAT(pNumerator, rat_zero); // pNumerator->pq is 1 one DUPRAT(pNumerator, rat_zero); // pNumerator->pq is 1 one
DUPRAT(pDenominator, rat_zero); // pDenominator->pq is 1 one DUPRAT(pDenominator, rat_zero); // pDenominator->pq is 1 one
@ -516,7 +516,7 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision)
} }
destroyrat(pNumerator); destroyrat(pNumerator);
destroyrat(pDenominator); destroyrat(pDenominator);
if (fBadExponent) if (fBadExponent)
{ {
throw( CALC_E_DOMAIN ); throw( CALC_E_DOMAIN );

View file

@ -73,17 +73,17 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
PRAT ratprec = nullptr; PRAT ratprec = nullptr;
PRAT ratRadix = nullptr; PRAT ratRadix = nullptr;
long oldprec; long oldprec;
// Set up constants and initial conditions // Set up constants and initial conditions
oldprec = precision; oldprec = precision;
ratprec = longtorat( oldprec ); ratprec = longtorat( oldprec );
// Find the best 'A' for convergence to the required precision. // Find the best 'A' for convergence to the required precision.
a=longtorat( radix ); a=longtorat( radix );
lograt(&a, precision); lograt(&a, precision);
mulrat(&a, ratprec, precision); mulrat(&a, ratprec, precision);
// Really is -ln(n)+1, but -ln(n) will be < 1 // Really is -ln(n)+1, but -ln(n) will be < 1
// if we scale n between 0.5 and 1.5 // if we scale n between 0.5 and 1.5
addrat(&a, rat_two, precision); addrat(&a, rat_two, precision);
DUPRAT(tmp,a); DUPRAT(tmp,a);
@ -91,9 +91,9 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
mulrat(&tmp, *pn, precision); mulrat(&tmp, *pn, precision);
addrat(&a, tmp, precision); addrat(&a, tmp, precision);
addrat(&a, rat_one, precision); addrat(&a, rat_one, precision);
// Calculate the necessary bump in precision and up the precision. // Calculate the necessary bump in precision and up the precision.
// The following code is equivalent to // The following code is equivalent to
// precision += ln(exp(a)*pow(a,n+1.5))-ln(radix)); // precision += ln(exp(a)*pow(a,n+1.5))-ln(radix));
DUPRAT(tmp,*pn); DUPRAT(tmp,*pn);
one_pt_five=longtorat( 3L ); one_pt_five=longtorat( 3L );
@ -110,7 +110,7 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
lograt( &tmp, precision); lograt( &tmp, precision);
subrat( &term, tmp, precision); subrat( &term, tmp, precision);
precision += rattolong( term, radix, precision); precision += rattolong( term, radix, precision);
// Set up initial terms for series, refer to series in above comment block. // Set up initial terms for series, refer to series in above comment block.
DUPRAT(factorial,rat_one); // Start factorial out with one DUPRAT(factorial,rat_one); // Start factorial out with one
count = longtonum( 0L, BASEX ); count = longtonum( 0L, BASEX );
@ -120,7 +120,7 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
// a2=a^2 // a2=a^2
DUPRAT(a2,a); DUPRAT(a2,a);
mulrat(&a2, a, precision); mulrat(&a2, a, precision);
// sum=(1/n)-(a/(n+1)) // sum=(1/n)-(a/(n+1))
DUPRAT(sum,rat_one); DUPRAT(sum,rat_one);
divrat(&sum, *pn, precision); divrat(&sum, *pn, precision);
@ -136,14 +136,14 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
divrat(&err, ratRadix, precision); divrat(&err, ratRadix, precision);
// Just get something not tiny in term // Just get something not tiny in term
DUPRAT(term, rat_two ); DUPRAT(term, rat_two );
// Loop until precision is reached, or asked to halt. // Loop until precision is reached, or asked to halt.
while ( !zerrat( term ) && rat_gt( term, err, precision) ) while ( !zerrat( term ) && rat_gt( term, err, precision) )
{ {
addrat(pn, rat_two, precision); addrat(pn, rat_two, precision);
// WARNING: mixing numbers and rationals here. // WARNING: mixing numbers and rationals here.
// for speed and efficiency. // for speed and efficiency.
INC(count); INC(count);
mulnumx(&(factorial->pp),count); mulnumx(&(factorial->pp),count);
@ -166,15 +166,15 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision)
DUPRAT(term,rat_one); DUPRAT(term,rat_one);
divrat( &term, *pn, precision); divrat( &term, *pn, precision);
subrat( &term, tmp, precision); subrat( &term, tmp, precision);
divrat (&term, factorial, precision); divrat (&term, factorial, precision);
addrat( &sum, term, precision); addrat( &sum, term, precision);
ABSRAT(term); ABSRAT(term);
} }
// Multiply by factor. // Multiply by factor.
mulrat( &sum, mpy, precision); mulrat( &sum, mpy, precision);
// And cleanup // And cleanup
precision = oldprec; precision = oldprec;
destroyrat(ratprec); destroyrat(ratprec);
@ -199,13 +199,13 @@ void factrat( PRAT *px, uint32_t radix, int32_t precision)
PRAT fact = nullptr; PRAT fact = nullptr;
PRAT frac = nullptr; PRAT frac = nullptr;
PRAT neg_rat_one = nullptr; PRAT neg_rat_one = nullptr;
if ( rat_gt( *px, rat_max_fact, precision) || rat_lt( *px, rat_min_fact, precision) ) if ( rat_gt( *px, rat_max_fact, precision) || rat_lt( *px, rat_min_fact, precision) )
{ {
// Don't attempt factorial of anything too large or small. // Don't attempt factorial of anything too large or small.
throw CALC_E_OVERFLOW; throw CALC_E_OVERFLOW;
} }
DUPRAT(fact,rat_one); DUPRAT(fact,rat_one);
DUPRAT(neg_rat_one,rat_one); DUPRAT(neg_rat_one,rat_one);
@ -226,7 +226,7 @@ void factrat( PRAT *px, uint32_t radix, int32_t precision)
mulrat( &fact, *px, precision); mulrat( &fact, *px, precision);
subrat( px, rat_one, precision); subrat( px, rat_one, precision);
} }
// Added to make numbers 'close enough' to integers use integer factorial. // Added to make numbers 'close enough' to integers use integer factorial.
if ( LOGRATRADIX(*px) <= -precision) if ( LOGRATRADIX(*px) <= -precision)
{ {

View file

@ -69,13 +69,13 @@ void _asinrat( PRAT *px, int32_t precision)
{ {
CREATETAYLOR(); CREATETAYLOR();
DUPRAT(pret,*px); DUPRAT(pret,*px);
DUPRAT(thisterm,*px); DUPRAT(thisterm,*px);
DUPNUM(n2,num_one); DUPNUM(n2,num_one);
do do
{ {
NEXTTERM(xx,MULNUM(n2) MULNUM(n2) NEXTTERM(xx,MULNUM(n2) MULNUM(n2)
INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision); INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} }
while ( !SMALL_ENOUGH_RAT( thisterm, precision) ); while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
@ -100,7 +100,7 @@ void asinrat( PRAT *px, uint32_t radix, int32_t precision)
(*px)->pp->sign = 1; (*px)->pp->sign = 1;
(*px)->pq->sign = 1; (*px)->pq->sign = 1;
// Avoid the really bad part of the asin curve near +/-1. // Avoid the really bad part of the asin curve near +/-1.
DUPRAT(phack,*px); DUPRAT(phack,*px);
subrat(&phack, rat_one, precision); subrat(&phack, rat_one, precision);
@ -185,15 +185,15 @@ void _acosrat( PRAT *px, int32_t precision)
{ {
CREATETAYLOR(); CREATETAYLOR();
createrat(thisterm); createrat(thisterm);
thisterm->pp=longtonum( 1L, BASEX ); thisterm->pp=longtonum( 1L, BASEX );
thisterm->pq=longtonum( 1L, BASEX ); thisterm->pq=longtonum( 1L, BASEX );
DUPNUM(n2,num_one); DUPNUM(n2,num_one);
do do
{ {
NEXTTERM(xx,MULNUM(n2) MULNUM(n2) NEXTTERM(xx,MULNUM(n2) MULNUM(n2)
INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision); INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} }
while ( !SMALL_ENOUGH_RAT( thisterm, precision) ); while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
@ -210,7 +210,7 @@ void acosrat( PRAT *px, uint32_t radix, int32_t precision)
(*px)->pp->sign = 1; (*px)->pp->sign = 1;
(*px)->pq->sign = 1; (*px)->pq->sign = 1;
if ( rat_equ( *px, rat_one, precision) ) if ( rat_equ( *px, rat_one, precision) )
{ {
if ( sgn == -1 ) if ( sgn == -1 )
@ -274,7 +274,7 @@ void _atanrat( PRAT *px, int32_t precision)
{ {
CREATETAYLOR(); CREATETAYLOR();
DUPRAT(pret,*px); DUPRAT(pret,*px);
DUPRAT(thisterm,*px); DUPRAT(thisterm,*px);
DUPNUM(n2,num_one); DUPNUM(n2,num_one);
@ -298,7 +298,7 @@ void atanrat( PRAT *px, uint32_t radix, int32_t precision)
(*px)->pp->sign = 1; (*px)->pp->sign = 1;
(*px)->pq->sign = 1; (*px)->pq->sign = 1;
if ( rat_gt( (*px), pt_eight_five, precision) ) if ( rat_gt( (*px), pt_eight_five, precision) )
{ {
if ( rat_gt( (*px), rat_two, precision) ) if ( rat_gt( (*px), rat_two, precision) )
@ -314,7 +314,7 @@ void atanrat( PRAT *px, uint32_t radix, int32_t precision)
subrat(px, tmpx, precision); subrat(px, tmpx, precision);
destroyrat( tmpx ); destroyrat( tmpx );
} }
else else
{ {
(*px)->pp->sign = sgn; (*px)->pp->sign = sgn;
DUPRAT(tmpx,*px); DUPRAT(tmpx,*px);

View file

@ -60,7 +60,7 @@ void asinhrat( PRAT *px, uint32_t radix, int32_t precision)
if ( rat_gt( *px, pt_eight_five, precision) || rat_lt( *px, neg_pt_eight_five, precision) ) if ( rat_gt( *px, pt_eight_five, precision) || rat_lt( *px, neg_pt_eight_five, precision) )
{ {
PRAT ptmp = nullptr; PRAT ptmp = nullptr;
DUPRAT(ptmp,(*px)); DUPRAT(ptmp,(*px));
mulrat(&ptmp, *px, precision); mulrat(&ptmp, *px, precision);
addrat(&ptmp, rat_one, precision); addrat(&ptmp, rat_one, precision);
rootrat(&ptmp, rat_two, radix, precision); rootrat(&ptmp, rat_two, radix, precision);
@ -73,14 +73,14 @@ void asinhrat( PRAT *px, uint32_t radix, int32_t precision)
CREATETAYLOR(); CREATETAYLOR();
xx->pp->sign *= -1; xx->pp->sign *= -1;
DUPRAT(pret,(*px)); DUPRAT(pret,(*px));
DUPRAT(thisterm,(*px)); DUPRAT(thisterm,(*px));
DUPNUM(n2,num_one); DUPNUM(n2,num_one);
do do
{ {
NEXTTERM(xx,MULNUM(n2) MULNUM(n2) NEXTTERM(xx,MULNUM(n2) MULNUM(n2)
INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision); INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
} }
while ( !SMALL_ENOUGH_RAT( thisterm, precision) ); while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
@ -99,7 +99,7 @@ void asinhrat( PRAT *px, uint32_t radix, int32_t precision)
// hyperbolic cose of // hyperbolic cose of
// RETURN: acosh of x in PRAT form. // RETURN: acosh of x in PRAT form.
// //
// EXPLANATION: This uses // EXPLANATION: This uses
// //
// acosh(x)=ln(x+sqrt(x^2-1)) // acosh(x)=ln(x+sqrt(x^2-1))
// //
@ -117,7 +117,7 @@ void acoshrat( PRAT *px, uint32_t radix, int32_t precision)
else else
{ {
PRAT ptmp = nullptr; PRAT ptmp = nullptr;
DUPRAT(ptmp,(*px)); DUPRAT(ptmp,(*px));
mulrat(&ptmp, *px, precision); mulrat(&ptmp, *px, precision);
subrat(&ptmp, rat_one, precision); subrat(&ptmp, rat_one, precision);
rootrat(&ptmp,rat_two, radix, precision); rootrat(&ptmp,rat_two, radix, precision);
@ -148,7 +148,7 @@ void atanhrat( PRAT *px, int32_t precision)
{ {
PRAT ptmp = nullptr; PRAT ptmp = nullptr;
DUPRAT(ptmp,(*px)); DUPRAT(ptmp,(*px));
subrat(&ptmp, rat_one, precision); subrat(&ptmp, rat_one, precision);
addrat(px, rat_one, precision); addrat(px, rat_one, precision);
divrat(px, ptmp, precision); divrat(px, ptmp, precision);

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -16,7 +16,7 @@
#include "pch.h" #include "pch.h"
#include "ratpak.h" #include "ratpak.h"
using namespace std;
void lshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) void lshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
@ -49,7 +49,7 @@ void rshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision)
intrat(pa, radix, precision); intrat(pa, radix, precision);
if ( !zernum( (*pa)->pp ) ) if ( !zernum( (*pa)->pp ) )
{ {
// If input is zero we're done. // If input is zero we're done.
if ( rat_lt( b, rat_min_exp, precision) ) if ( rat_lt( b, rat_min_exp, precision) )
{ {
@ -155,11 +155,11 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func )
pchc = c->mant; pchc = c->mant;
for ( ;cdigits > 0; cdigits--, mexp++ ) for ( ;cdigits > 0; cdigits--, mexp++ )
{ {
da = ( ( ( mexp >= a->exp ) && ( cdigits + a->exp - c->exp > da = ( ( ( mexp >= a->exp ) && ( cdigits + a->exp - c->exp >
(c->cdigit - a->cdigit) ) ) ? (c->cdigit - a->cdigit) ) ) ?
*pcha++ : 0 ); *pcha++ : 0 );
db = ( ( ( mexp >= b->exp ) && ( cdigits + b->exp - c->exp > db = ( ( ( mexp >= b->exp ) && ( cdigits + b->exp - c->exp >
(c->cdigit - b->cdigit) ) ) ? (c->cdigit - b->cdigit) ) ) ?
*pchb++ : 0 ); *pchb++ : 0 );
switch ( func ) switch ( func )
{ {
@ -205,15 +205,14 @@ void modrat( PRAT *pa, PRAT b )
throw CALC_E_INDEFINITE; throw CALC_E_INDEFINITE;
} }
DUPRAT(tmp,b); DUPRAT(tmp,b);
mulnumx( &((*pa)->pp), tmp->pq ); mulnumx( &((*pa)->pp), tmp->pq );
mulnumx( &(tmp->pp), (*pa)->pq ); mulnumx( &(tmp->pp), (*pa)->pq );
remnum( &((*pa)->pp), tmp->pp, BASEX ); remnum( &((*pa)->pp), tmp->pp, BASEX );
mulnumx( &((*pa)->pq), tmp->pq ); mulnumx( &((*pa)->pq), tmp->pq );
//Get *pa back in the integer over integer form. // Get *pa back in the integer over integer form.
RENORMALIZE(*pa); RENORMALIZE(*pa);
destroyrat( tmp ); destroyrat( tmp );
} }

View file

@ -2,20 +2,20 @@
// Licensed under the MIT License. // Licensed under the MIT License.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Package Title ratpak // Package Title ratpak
// File num.c // File num.c
// Copyright (C) 1995-97 Microsoft // Copyright (C) 1995-97 Microsoft
// Date 01-16-95 // Date 01-16-95
// //
// //
// Description // Description
// //
// Contains number routines for add, mul, div, rem and other support // Contains number routines for add, mul, div, rem and other support
// and longs. // and longs.
// //
// Special Information // Special Information
// //
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "pch.h" #include "pch.h"
#include "ratpak.h" #include "ratpak.h"
@ -76,8 +76,8 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
long fcomplb = 0; // fcomplb is a flag to signal b is negative. long fcomplb = 0; // fcomplb is a flag to signal b is negative.
a=*pa; a=*pa;
// Calculate the overlap of the numbers after alignment, this includes // Calculate the overlap of the numbers after alignment, this includes
// necessary padding 0's // necessary padding 0's
cdigits = max( a->cdigit+a->exp, b->cdigit+b->exp ) - cdigits = max( a->cdigit+a->exp, b->cdigit+b->exp ) -
@ -90,7 +90,7 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
pcha = a->mant; pcha = a->mant;
pchb = b->mant; pchb = b->mant;
pchc = c->mant; pchc = c->mant;
// Figure out the sign of the numbers // Figure out the sign of the numbers
if ( a->sign != b->sign ) if ( a->sign != b->sign )
{ {
@ -98,21 +98,21 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
fcompla = ( a->sign == -1 ); fcompla = ( a->sign == -1 );
fcomplb = ( b->sign == -1 ); fcomplb = ( b->sign == -1 );
} }
// Loop over all the digits, real and 0 padded. Here we know a and b are // Loop over all the digits, real and 0 padded. Here we know a and b are
// aligned // aligned
for ( ;cdigits > 0; cdigits--, mexp++ ) for ( ;cdigits > 0; cdigits--, mexp++ )
{ {
// Get digit from a, taking padding into account. // Get digit from a, taking padding into account.
da = ( ( ( mexp >= a->exp ) && ( cdigits + a->exp - c->exp > da = ( ( ( mexp >= a->exp ) && ( cdigits + a->exp - c->exp >
(c->cdigit - a->cdigit) ) ) ? (c->cdigit - a->cdigit) ) ) ?
*pcha++ : 0 ); *pcha++ : 0 );
// Get digit from b, taking padding into account. // Get digit from b, taking padding into account.
db = ( ( ( mexp >= b->exp ) && ( cdigits + b->exp - c->exp > db = ( ( ( mexp >= b->exp ) && ( cdigits + b->exp - c->exp >
(c->cdigit - b->cdigit) ) ) ? (c->cdigit - b->cdigit) ) ) ?
*pchb++ : 0 ); *pchb++ : 0 );
// Handle complementing for a and b digit. Might be a better way, but // Handle complementing for a and b digit. Might be a better way, but
// haven't found it yet. // haven't found it yet.
if ( fcompla ) if ( fcompla )
@ -123,20 +123,20 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
{ {
db = (MANTTYPE)(radix) - 1 - db; db = (MANTTYPE)(radix) - 1 - db;
} }
// Update carry as necessary // Update carry as necessary
cy = da + db + cy; cy = da + db + cy;
*pchc++ = (MANTTYPE)(cy % (MANTTYPE)radix); *pchc++ = (MANTTYPE)(cy % (MANTTYPE)radix);
cy /= (MANTTYPE)radix; cy /= (MANTTYPE)radix;
} }
// Handle carry from last sum as extra digit // Handle carry from last sum as extra digit
if ( cy && !(fcompla || fcomplb) ) if ( cy && !(fcompla || fcomplb) )
{ {
*pchc++ = cy; *pchc++ = cy;
c->cdigit++; c->cdigit++;
} }
// Compute sign of result // Compute sign of result
if ( !(fcompla || fcomplb) ) if ( !(fcompla || fcomplb) )
{ {
@ -150,14 +150,14 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
} }
else else
{ {
// In this particular case an overflow or underflow has occurred // In this particular case an overflow or underflow has occurred
// and all the digits need to be complemented, at one time an // and all the digits need to be complemented, at one time an
// attempt to handle this above was made, it turned out to be much // attempt to handle this above was made, it turned out to be much
// slower on average. // slower on average.
c->sign = -1; c->sign = -1;
cy = 1; cy = 1;
for ( ( cdigits = c->cdigit ), (pchc = c->mant); for ( ( cdigits = c->cdigit ), (pchc = c->mant);
cdigits > 0; cdigits > 0;
cdigits-- ) cdigits-- )
{ {
cy = (MANTTYPE)radix - (MANTTYPE)1 - *pchc + cy; cy = (MANTTYPE)radix - (MANTTYPE)1 - *pchc + cy;
@ -166,7 +166,7 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
} }
} }
} }
// Remove leading zeros, remember digits are in order of // Remove leading zeros, remember digits are in order of
// increasing significance. i.e. 100 would be 0,0,1 // increasing significance. i.e. 100 would be 0,0,1
while ( c->cdigit > 1 && *(--pchc) == 0 ) while ( c->cdigit > 1 && *(--pchc) == 0 )
@ -231,7 +231,7 @@ void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
MANTTYPE da = 0; // da is the digit from the fist number. MANTTYPE da = 0; // da is the digit from the fist number.
TWO_MANTTYPE cy = 0; // cy is the carry resulting from the addition of TWO_MANTTYPE cy = 0; // cy is the carry resulting from the addition of
// a multiplied row into the result. // a multiplied row into the result.
TWO_MANTTYPE mcy = 0; // mcy is the resultant from a single TWO_MANTTYPE mcy = 0; // mcy is the resultant from a single
// multiply, AND the carry of that multiply. // multiply, AND the carry of that multiply.
long icdigit = 0; // Index of digit being calculated in final result. long icdigit = 0; // Index of digit being calculated in final result.
@ -249,8 +249,8 @@ void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
{ {
da = *pcha++; da = *pcha++;
pchb = b->mant; pchb = b->mant;
// Shift pchc, and pchcoffset, one for each digit // Shift pchc, and pchcoffset, one for each digit
pchc = pchcoffset++; pchc = pchcoffset++;
for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- ) for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- )
@ -268,23 +268,23 @@ void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
// If result is nonzero, or while result of carry is nonzero... // If result is nonzero, or while result of carry is nonzero...
while ( mcy || cy ) while ( mcy || cy )
{ {
// update carry from addition(s) and multiply. // update carry from addition(s) and multiply.
cy += (TWO_MANTTYPE)pchc[icdigit]+(mcy%(TWO_MANTTYPE)radix); cy += (TWO_MANTTYPE)pchc[icdigit]+(mcy%(TWO_MANTTYPE)radix);
// update result digit from // update result digit from
pchc[icdigit++]=(MANTTYPE)(cy%(TWO_MANTTYPE)radix); pchc[icdigit++]=(MANTTYPE)(cy%(TWO_MANTTYPE)radix);
// update carries from // update carries from
mcy /= (TWO_MANTTYPE)radix; mcy /= (TWO_MANTTYPE)radix;
cy /= (TWO_MANTTYPE)radix; cy /= (TWO_MANTTYPE)radix;
} }
pchb++; pchb++;
pchc++; pchc++;
} }
} }
// prevent different kinds of zeros, by stripping leading duplicate zeros. // prevent different kinds of zeros, by stripping leading duplicate zeros.
// digits are in order of increasing significance. // digits are in order of increasing significance.
while ( c->cdigit > 1 && c->mant[c->cdigit-1] == 0 ) while ( c->cdigit > 1 && c->mant[c->cdigit-1] == 0 )
@ -317,7 +317,7 @@ void remnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
{ {
PNUMBER tmp = nullptr; // tmp is the working remainder. PNUMBER tmp = nullptr; // tmp is the working remainder.
PNUMBER lasttmp = nullptr; // lasttmp is the last remainder which worked. PNUMBER lasttmp = nullptr; // lasttmp is the last remainder which worked.
// Once *pa is less than b, *pa is the remainder. // Once *pa is less than b, *pa is the remainder.
while ( !lessnum( *pa, b ) ) while ( !lessnum( *pa, b ) )
{ {
@ -336,20 +336,20 @@ void remnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
destroynum( lasttmp ); destroynum( lasttmp );
lasttmp=longtonum( 0, radix); lasttmp=longtonum( 0, radix);
while ( lessnum( tmp, *pa ) ) while ( lessnum( tmp, *pa ) )
{ {
DUPNUM( lasttmp, tmp ); DUPNUM( lasttmp, tmp );
addnum( &tmp, tmp, radix); addnum( &tmp, tmp, radix);
} }
if ( lessnum( *pa, tmp ) ) if ( lessnum( *pa, tmp ) )
{ {
// too far, back up... // too far, back up...
destroynum( tmp ); destroynum( tmp );
tmp=lasttmp; tmp=lasttmp;
lasttmp= nullptr; lasttmp= nullptr;
} }
// Subtract the working remainder from the remainder holder. // Subtract the working remainder from the remainder holder.
tmp->sign = -1*(*pa)->sign; tmp->sign = -1*(*pa)->sign;
addnum( pa, tmp, radix); addnum( pa, tmp, radix);
@ -357,7 +357,7 @@ void remnum( PNUMBER *pa, PNUMBER b, uint32_t radix)
destroynum( tmp ); destroynum( tmp );
destroynum( lasttmp ); destroynum( lasttmp );
} }
} }
@ -381,7 +381,7 @@ void __inline divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
{ {
if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 ) if ( b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0 )
{ {
// b is not one // b is not one
_divnum( pa, b, radix, precision); _divnum( pa, b, radix, precision);
} }
@ -418,7 +418,7 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision)
tmp->sign = a->sign; tmp->sign = a->sign;
rem->exp = b->cdigit + b->exp - rem->cdigit; rem->exp = b->cdigit + b->exp - rem->cdigit;
// Build a table of multiplications of the divisor, this is quicker for // Build a table of multiplications of the divisor, this is quicker for
// more than radix 'digits' // more than radix 'digits'
list<PNUMBER> numberList{ longtonum(0L, radix) }; list<PNUMBER> numberList{ longtonum(0L, radix) };
for (unsigned long i = 1; i < radix; i++) for (unsigned long i = 1; i < radix; i++)
@ -535,21 +535,21 @@ bool equnum( PNUMBER a, PNUMBER b )
pb += b->cdigit - 1; pb += b->cdigit - 1;
cdigits = max( a->cdigit, b->cdigit ); cdigits = max( a->cdigit, b->cdigit );
ccdigits = cdigits; ccdigits = cdigits;
// Loop over all digits until we run out of digits or there is a // Loop over all digits until we run out of digits or there is a
// difference in the digits. // difference in the digits.
for ( ;cdigits > 0; cdigits-- ) for ( ;cdigits > 0; cdigits-- )
{ {
da = ( (cdigits > (ccdigits - a->cdigit) ) ? da = ( (cdigits > (ccdigits - a->cdigit) ) ?
*pa-- : 0 ); *pa-- : 0 );
db = ( (cdigits > (ccdigits - b->cdigit) ) ? db = ( (cdigits > (ccdigits - b->cdigit) ) ?
*pb-- : 0 ); *pb-- : 0 );
if ( da != db ) if ( da != db )
{ {
return false; return false;
} }
} }
// In this case, they are equal. // In this case, they are equal.
return true; return true;
} }
@ -604,9 +604,9 @@ bool lessnum( PNUMBER a, PNUMBER b )
ccdigits = cdigits; ccdigits = cdigits;
for ( ;cdigits > 0; cdigits-- ) for ( ;cdigits > 0; cdigits-- )
{ {
da = ( (cdigits > (ccdigits - a->cdigit) ) ? da = ( (cdigits > (ccdigits - a->cdigit) ) ?
*pa-- : 0 ); *pa-- : 0 );
db = ( (cdigits > (ccdigits - b->cdigit) ) ? db = ( (cdigits > (ccdigits - b->cdigit) ) ?
*pb-- : 0 ); *pb-- : 0 );
diff = da-db; diff = da-db;
if ( diff ) if ( diff )
@ -639,8 +639,8 @@ bool zernum( PNUMBER a )
MANTTYPE *pcha; MANTTYPE *pcha;
length = a->cdigit; length = a->cdigit;
pcha = a->mant; pcha = a->mant;
// loop over all the digits until you find a nonzero or until you run // loop over all the digits until you find a nonzero or until you run
// out of digits // out of digits
while ( length-- > 0 ) while ( length-- > 0 )
{ {

View file

@ -56,7 +56,7 @@ void gcdrat( PRAT *pa, int32_t precision)
destroynum( pgcd ); destroynum( pgcd );
*pa=a; *pa=a;
RENORMALIZE(*pa); RENORMALIZE(*pa);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -82,7 +82,7 @@ void fracrat( PRAT *pa , uint32_t radix, int32_t precision)
remnum( &((*pa)->pp), (*pa)->pq, BASEX ); remnum( &((*pa)->pp), (*pa)->pq, BASEX );
//Get *pa back in the integer over integer form. // Get *pa back in the integer over integer form.
RENORMALIZE(*pa); RENORMALIZE(*pa);
} }
@ -100,7 +100,7 @@ void fracrat( PRAT *pa , uint32_t radix, int32_t precision)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void mulrat( PRAT *pa, PRAT b, int32_t precision) void mulrat( PRAT *pa, PRAT b, int32_t precision)
{ {
// Only do the multiply if it isn't zero. // Only do the multiply if it isn't zero.
if ( !zernum( (*pa)->pp ) ) if ( !zernum( (*pa)->pp ) )
@ -170,7 +170,7 @@ void divrat( PRAT *pa, PRAT b, int32_t precision)
#ifdef DIVGCD #ifdef DIVGCD
gcdrat( pa ); gcdrat( pa );
#endif #endif
} }
@ -215,13 +215,13 @@ void addrat( PRAT *pa, PRAT b, int32_t precision)
if ( equnum( (*pa)->pq, b->pq ) ) if ( equnum( (*pa)->pq, b->pq ) )
{ {
// Very special case, q's match., // Very special case, q's match.,
// make sure signs are involved in the calculation // make sure signs are involved in the calculation
// we have to do this since the optimization here is only // we have to do this since the optimization here is only
// working with the top half of the rationals. // working with the top half of the rationals.
(*pa)->pp->sign *= (*pa)->pq->sign; (*pa)->pp->sign *= (*pa)->pq->sign;
(*pa)->pq->sign = 1; (*pa)->pq->sign = 1;
b->pp->sign *= b->pq->sign; b->pp->sign *= b->pq->sign;
b->pq->sign = 1; b->pq->sign = 1;
addnum( &((*pa)->pp), b->pp, BASEX ); addnum( &((*pa)->pp), b->pp, BASEX );
} }
@ -236,15 +236,15 @@ void addrat( PRAT *pa, PRAT b, int32_t precision)
destroynum( (*pa)->pq ); destroynum( (*pa)->pq );
(*pa)->pq = bot; (*pa)->pq = bot;
trimit(pa, precision); trimit(pa, precision);
// Get rid of negative zeros here. // Get rid of negative zeros here.
(*pa)->pp->sign *= (*pa)->pq->sign; (*pa)->pp->sign *= (*pa)->pq->sign;
(*pa)->pq->sign = 1; (*pa)->pq->sign = 1;
} }
#ifdef ADDGCD #ifdef ADDGCD
gcdrat( pa ); gcdrat( pa );
#endif #endif
} }
@ -264,7 +264,7 @@ void addrat( PRAT *pa, PRAT b, int32_t precision)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void rootrat( PRAT *py, PRAT n, uint32_t radix, int32_t precision) void rootrat( PRAT *py, PRAT n, uint32_t radix, int32_t precision)
{ {
// Initialize 1/n // Initialize 1/n
PRAT oneovern= nullptr; PRAT oneovern= nullptr;
DUPRAT(oneovern,rat_one); DUPRAT(oneovern,rat_one);

View file

@ -1,480 +1,482 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
// Autogenerated by _dumprawrat in support.c #pragma once
NUMBER init_num_one= {
// Autogenerated by _dumprawrat in support.cpp
inline const NUMBER init_num_one= {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_num_two= { inline const NUMBER init_num_two= {
1, 1,
1, 1,
0, 0,
{ 2,} { 2,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_num_five= { inline const NUMBER init_num_five= {
1, 1,
1, 1,
0, 0,
{ 5,} { 5,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_num_six= { inline const NUMBER init_num_six= {
1, 1,
1, 1,
0, 0,
{ 6,} { 6,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_num_ten= { inline const NUMBER init_num_ten= {
1, 1,
1, 1,
0, 0,
{ 10,} { 10,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_smallest = { inline const NUMBER init_p_rat_smallest = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
NUMBER init_q_rat_smallest = { inline const NUMBER init_q_rat_smallest = {
1, 1,
4, 4,
0, 0,
{ 0, 190439170, 901055854, 10097,} { 0, 190439170, 901055854, 10097,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_negsmallest = { inline const NUMBER init_p_rat_negsmallest = {
-1, -1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
NUMBER init_q_rat_negsmallest = { inline const NUMBER init_q_rat_negsmallest = {
1, 1,
4, 4,
0, 0,
{ 0, 190439170, 901055854, 10097,} { 0, 190439170, 901055854, 10097,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_pt_eight_five = { inline const NUMBER init_p_pt_eight_five = {
1, 1,
1, 1,
0, 0,
{ 85,} { 85,}
}; };
NUMBER init_q_pt_eight_five = { inline const NUMBER init_q_pt_eight_five = {
1, 1,
1, 1,
0, 0,
{ 100,} { 100,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_six = { inline const NUMBER init_p_rat_six = {
1, 1,
1, 1,
0, 0,
{ 6,} { 6,}
}; };
NUMBER init_q_rat_six = { inline const NUMBER init_q_rat_six = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_two = { inline const NUMBER init_p_rat_two = {
1, 1,
1, 1,
0, 0,
{ 2,} { 2,}
}; };
NUMBER init_q_rat_two = { inline const NUMBER init_q_rat_two = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_zero = { inline const NUMBER init_p_rat_zero = {
1, 1,
1, 1,
0, 0,
{ 0,} { 0,}
}; };
NUMBER init_q_rat_zero = { inline const NUMBER init_q_rat_zero = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_one = { inline const NUMBER init_p_rat_one = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
NUMBER init_q_rat_one = { inline const NUMBER init_q_rat_one = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_neg_one = { inline const NUMBER init_p_rat_neg_one = {
-1, -1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
NUMBER init_q_rat_neg_one = { inline const NUMBER init_q_rat_neg_one = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_half = { inline const NUMBER init_p_rat_half = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
NUMBER init_q_rat_half = { inline const NUMBER init_q_rat_half = {
1, 1,
1, 1,
0, 0,
{ 2,} { 2,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_ten = { inline const NUMBER init_p_rat_ten = {
1, 1,
1, 1,
0, 0,
{ 10,} { 10,}
}; };
NUMBER init_q_rat_ten = { inline const NUMBER init_q_rat_ten = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_pi = { inline const NUMBER init_p_pi = {
1, 1,
6, 6,
0, 0,
{ 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,} { 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,}
}; };
NUMBER init_q_pi = { inline const NUMBER init_q_pi = {
1, 1,
6, 6,
0, 0,
{ 1288380402, 1120116153, 1860424692, 1944118326, 1583591604, 2,} { 1288380402, 1120116153, 1860424692, 1944118326, 1583591604, 2,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_two_pi = { inline const NUMBER init_p_two_pi = {
1, 1,
6, 6,
0, 0,
{ 251055792, 567796700, 1773504224, 1198217877, 428852897, 17,} { 251055792, 567796700, 1773504224, 1198217877, 428852897, 17,}
}; };
NUMBER init_q_two_pi = { inline const NUMBER init_q_two_pi = {
1, 1,
6, 6,
0, 0,
{ 1288380402, 1120116153, 1860424692, 1944118326, 1583591604, 2,} { 1288380402, 1120116153, 1860424692, 1944118326, 1583591604, 2,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_pi_over_two = { inline const NUMBER init_p_pi_over_two = {
1, 1,
6, 6,
0, 0,
{ 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,} { 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,}
}; };
NUMBER init_q_pi_over_two = { inline const NUMBER init_q_pi_over_two = {
1, 1,
6, 6,
0, 0,
{ 429277156, 92748659, 1573365737, 1740753005, 1019699561, 5,} { 429277156, 92748659, 1573365737, 1740753005, 1019699561, 5,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_one_pt_five_pi = { inline const NUMBER init_p_one_pt_five_pi = {
1, 1,
6, 6,
0, 0,
{ 1241201312, 270061909, 1051574664, 1924965045, 1340320627, 70,} { 1241201312, 270061909, 1051574664, 1924965045, 1340320627, 70,}
}; };
NUMBER init_q_one_pt_five_pi = { inline const NUMBER init_q_one_pt_five_pi = {
1, 1,
6, 6,
0, 0,
{ 1579671539, 1837970263, 1067644340, 523549916, 2119366659, 14,} { 1579671539, 1837970263, 1067644340, 523549916, 2119366659, 14,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_e_to_one_half = { inline const NUMBER init_p_e_to_one_half = {
1, 1,
6, 6,
0, 0,
{ 256945612, 216219427, 223516738, 477442596, 581063757, 23,} { 256945612, 216219427, 223516738, 477442596, 581063757, 23,}
}; };
NUMBER init_q_e_to_one_half = { inline const NUMBER init_q_e_to_one_half = {
1, 1,
6, 6,
0, 0,
{ 1536828363, 698484484, 1127331835, 224219346, 245499408, 14,} { 1536828363, 698484484, 1127331835, 224219346, 245499408, 14,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_exp = { inline const NUMBER init_p_rat_exp = {
1, 1,
6, 6,
0, 0,
{ 943665199, 1606559160, 1094967530, 1759391384, 1671799163, 1123581,} { 943665199, 1606559160, 1094967530, 1759391384, 1671799163, 1123581,}
}; };
NUMBER init_q_rat_exp = { inline const NUMBER init_q_rat_exp = {
1, 1,
6, 6,
0, 0,
{ 879242208, 2022880100, 617392930, 1374929092, 1367479163, 413342,} { 879242208, 2022880100, 617392930, 1374929092, 1367479163, 413342,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_ln_ten = { inline const NUMBER init_p_ln_ten = {
1, 1,
6, 6,
0, 0,
{ 2086268922, 165794492, 1416063951, 1851428830, 1893239400, 65366841,} { 2086268922, 165794492, 1416063951, 1851428830, 1893239400, 65366841,}
}; };
NUMBER init_q_ln_ten = { inline const NUMBER init_q_ln_ten = {
1, 1,
6, 6,
0, 0,
{ 26790652, 564532679, 783998273, 216030448, 1564709968, 28388458,} { 26790652, 564532679, 783998273, 216030448, 1564709968, 28388458,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_ln_two = { inline const NUMBER init_p_ln_two = {
1, 1,
6, 6,
0, 0,
{ 1789230241, 1057927868, 715399197, 908801241, 1411265331, 3,} { 1789230241, 1057927868, 715399197, 908801241, 1411265331, 3,}
}; };
NUMBER init_q_ln_two = { inline const NUMBER init_q_ln_two = {
1, 1,
6, 6,
0, 0,
{ 1559869847, 1930657510, 1228561531, 219003871, 593099283, 5,} { 1559869847, 1930657510, 1228561531, 219003871, 593099283, 5,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rad_to_deg = { inline const NUMBER init_p_rad_to_deg = {
1, 1,
6, 6,
0, 0,
{ 2127722024, 1904928383, 2016479213, 2048947859, 1578647346, 492,} { 2127722024, 1904928383, 2016479213, 2048947859, 1578647346, 492,}
}; };
NUMBER init_q_rad_to_deg = { inline const NUMBER init_q_rad_to_deg = {
1, 1,
6, 6,
0, 0,
{ 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,} { 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rad_to_grad = { inline const NUMBER init_p_rad_to_grad = {
1, 1,
6, 6,
0, 0,
{ 2125526288, 684931327, 570267400, 129125085, 1038224725, 547,} { 2125526288, 684931327, 570267400, 129125085, 1038224725, 547,}
}; };
NUMBER init_q_rad_to_grad = { inline const NUMBER init_q_rad_to_grad = {
1, 1,
6, 6,
0, 0,
{ 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,} { 125527896, 283898350, 1960493936, 1672850762, 1288168272, 8,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_qword = { inline const NUMBER init_p_rat_qword = {
1, 1,
3, 3,
0, 0,
{ 2147483647, 2147483647, 3,} { 2147483647, 2147483647, 3,}
}; };
NUMBER init_q_rat_qword = { inline const NUMBER init_q_rat_qword = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_dword = { inline const NUMBER init_p_rat_dword = {
1, 1,
2, 2,
0, 0,
{ 2147483647, 1,} { 2147483647, 1,}
}; };
NUMBER init_q_rat_dword = { inline const NUMBER init_q_rat_dword = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_max_long = { inline const NUMBER init_p_rat_max_long = {
1, 1,
1, 1,
0, 0,
{ 2147483647,} { 2147483647,}
}; };
NUMBER init_q_rat_max_long = { inline const NUMBER init_q_rat_max_long = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_min_long = { inline const NUMBER init_p_rat_min_long = {
-1, -1,
2, 2,
0, 0,
{ 0, 1,} { 0, 1,}
}; };
NUMBER init_q_rat_min_long = { inline const NUMBER init_q_rat_min_long = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_word = { inline const NUMBER init_p_rat_word = {
1, 1,
1, 1,
0, 0,
{ 65535,} { 65535,}
}; };
NUMBER init_q_rat_word = { inline const NUMBER init_q_rat_word = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_byte = { inline const NUMBER init_p_rat_byte = {
1, 1,
1, 1,
0, 0,
{ 255,} { 255,}
}; };
NUMBER init_q_rat_byte = { inline const NUMBER init_q_rat_byte = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_400 = { inline const NUMBER init_p_rat_400 = {
1, 1,
1, 1,
0, 0,
{ 400,} { 400,}
}; };
NUMBER init_q_rat_400 = { inline const NUMBER init_q_rat_400 = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_360 = { inline const NUMBER init_p_rat_360 = {
1, 1,
1, 1,
0, 0,
{ 360,} { 360,}
}; };
NUMBER init_q_rat_360 = { inline const NUMBER init_q_rat_360 = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_200 = { inline const NUMBER init_p_rat_200 = {
1, 1,
1, 1,
0, 0,
{ 200,} { 200,}
}; };
NUMBER init_q_rat_200 = { inline const NUMBER init_q_rat_200 = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_180 = { inline const NUMBER init_p_rat_180 = {
1, 1,
1, 1,
0, 0,
{ 180,} { 180,}
}; };
NUMBER init_q_rat_180 = { inline const NUMBER init_q_rat_180 = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_max_exp = { inline const NUMBER init_p_rat_max_exp = {
1, 1,
1, 1,
0, 0,
{ 100000,} { 100000,}
}; };
NUMBER init_q_rat_max_exp = { inline const NUMBER init_q_rat_max_exp = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_min_exp = { inline const NUMBER init_p_rat_min_exp = {
-1, -1,
1, 1,
0, 0,
{ 100000,} { 100000,}
}; };
NUMBER init_q_rat_min_exp = { inline const NUMBER init_q_rat_min_exp = {
1, 1,
1, 1,
0, 0,
{ 1,} { 1,}
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_max_fact = { inline const NUMBER init_p_rat_max_fact = {
1, 1,
1, 1,
0, 0,
{ 3249, } { 3249, }
}; };
NUMBER init_q_rat_max_fact = { inline const NUMBER init_q_rat_max_fact = {
1, 1,
1, 1,
0, 0,
{ 1, } { 1, }
}; };
// Autogenerated by _dumprawrat in support.c // Autogenerated by _dumprawrat in support.cpp
NUMBER init_p_rat_min_fact = { inline const NUMBER init_p_rat_min_fact = {
-1, -1,
1, 1,
0, 0,
{ 1000, } { 1000, }
}; };
NUMBER init_q_rat_min_fact = { inline const NUMBER init_q_rat_min_fact = {
1, 1,
1, 1,
0, 0,

View file

@ -225,7 +225,7 @@ memmove( (x)->pp->mant, &((x)->pp->mant[trim]), sizeof(MANTTYPE)*((x)->pp->cdigi
(x)->pp->cdigit -= trim; \ (x)->pp->cdigit -= trim; \
(x)->pp->exp += trim; \ (x)->pp->exp += trim; \
} \ } \
trim = min((x)->pp->exp,(x)->pq->exp);\ trim = std::min((x)->pp->exp,(x)->pq->exp);\
(x)->pp->exp -= trim;\ (x)->pp->exp -= trim;\
(x)->pq->exp -= trim;\ (x)->pq->exp -= trim;\
} }
@ -411,7 +411,7 @@ extern void tanrat( _Inout_ PRAT *px, uint32_t radix, int32_t precision);
// angle type // angle type
extern void tananglerat( _Inout_ PRAT *px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision); extern void tananglerat( _Inout_ PRAT *px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
extern void _dupnum(_In_ PNUMBER dest, _In_ PNUMBER src); extern void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER * const src);
extern void _destroynum( _In_ PNUMBER pnum ); extern void _destroynum( _In_ PNUMBER pnum );
extern void _destroyrat( _In_ PRAT prat ); extern void _destroyrat( _In_ PRAT prat );

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -31,8 +31,8 @@ static int cbitsofprecision = 0;
#define READRAWNUM(v) #define READRAWNUM(v)
#define DUMPRAWRAT(v) _dumprawrat(#v,v, wcout) #define DUMPRAWRAT(v) _dumprawrat(#v,v, wcout)
#define DUMPRAWNUM(v) fprintf( stderr, \ #define DUMPRAWNUM(v) fprintf( stderr, \
"// Autogenerated by _dumprawrat in support.c\n" ); \ "// Autogenerated by _dumprawrat in support.cpp\n" ); \
fprintf( stderr, "NUMBER init_" #v "= {\n" ); \ fprintf( stderr, "inline const NUMBER init_" #v "= {\n" ); \
_dumprawnum(v, wcout); \ _dumprawnum(v, wcout); \
fprintf( stderr, "};\n" ) fprintf( stderr, "};\n" )
@ -58,7 +58,7 @@ static int cbitsofprecision = RATIO_FOR_DECIMAL * DECIMAL * CALC_DECIMAL_DIGITS_
#endif #endif
bool g_ftrueinfinite = false; // Set to true if you don't want bool g_ftrueinfinite = false; // Set to true if you don't want
// chopping internally // chopping internally
// precision used internally // precision used internally
@ -119,8 +119,8 @@ PRAT rat_max_long= nullptr; // max signed long
void ChangeConstants(uint32_t radix, int32_t precision) void ChangeConstants(uint32_t radix, int32_t precision)
{ {
// ratio is set to the number of digits in the current radix, you can get // ratio is set to the number of digits in the current radix, you can get
// in the internal BASEX radix, this is important for length calculations // in the internal BASEX radix, this is important for length calculations
// in translating from radix to BASEX and back. // in translating from radix to BASEX and back.
uint64_t limit = static_cast<uint64_t>(BASEX) / static_cast<uint64_t>(radix); uint64_t limit = static_cast<uint64_t>(BASEX) / static_cast<uint64_t>(radix);
@ -213,7 +213,7 @@ void ChangeConstants(uint32_t radix, int32_t precision)
cbitsofprecision = g_ratio * radix * precision; cbitsofprecision = g_ratio * radix * precision;
// Apparently when dividing 180 by pi, another (internal) digit of // Apparently when dividing 180 by pi, another (internal) digit of
// precision is needed. // precision is needed.
long extraPrecision = precision + g_ratio; long extraPrecision = precision + g_ratio;
DUPRAT(pi, rat_half); DUPRAT(pi, rat_half);
@ -348,7 +348,7 @@ bool rat_ge( PRAT a, PRAT b, int32_t precision)
b->pp->sign *= -1; b->pp->sign *= -1;
addrat( &rattmp, b, precision); addrat( &rattmp, b, precision);
b->pp->sign *= -1; b->pp->sign *= -1;
bool bret = ( zernum( rattmp->pp ) || bool bret = ( zernum( rattmp->pp ) ||
rattmp->pp->sign * rattmp->pq->sign == 1 ); rattmp->pp->sign * rattmp->pq->sign == 1 );
destroyrat( rattmp ); destroyrat( rattmp );
return( bret ); return( bret );
@ -472,10 +472,10 @@ void scale( PRAT *px, PRAT scalefact, uint32_t radix, int32_t precision )
{ {
PRAT pret = nullptr; PRAT pret = nullptr;
DUPRAT(pret,*px); DUPRAT(pret,*px);
// Logscale is a quick way to tell how much extra precision is needed for // Logscale is a quick way to tell how much extra precision is needed for
// scaling by scalefact. // scaling by scalefact.
long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) - long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) -
(pret->pq->cdigit+pret->pq->exp) ); (pret->pq->cdigit+pret->pq->exp) );
if ( logscale > 0 ) if ( logscale > 0 )
{ {
@ -508,9 +508,9 @@ void scale2pi( PRAT *px, uint32_t radix, int32_t precision )
PRAT my_two_pi = nullptr; PRAT my_two_pi = nullptr;
DUPRAT(pret,*px); DUPRAT(pret,*px);
// Logscale is a quick way to tell how much extra precision is needed for // Logscale is a quick way to tell how much extra precision is needed for
// scaling by 2 pi. // scaling by 2 pi.
long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) - long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) -
(pret->pq->cdigit+pret->pq->exp) ); (pret->pq->cdigit+pret->pq->exp) );
if ( logscale > 0 ) if ( logscale > 0 )
{ {
@ -663,16 +663,16 @@ void _readconstants( void )
// ARGUMENTS: PRAT *px, long precision // ARGUMENTS: PRAT *px, long precision
// //
// //
// DESCRIPTION: Chops off digits from rational numbers to avoid time // DESCRIPTION: Chops off digits from rational numbers to avoid time
// explosions in calculations of functions using series. // explosions in calculations of functions using series.
// It can be shown that it is enough to only keep the first n digits // It can be shown that it is enough to only keep the first n digits
// of the largest of p or q in the rational p over q form, and of course // of the largest of p or q in the rational p over q form, and of course
// scale the smaller by the same number of digits. This will give you // scale the smaller by the same number of digits. This will give you
// n-1 digits of accuracy. This dramatically speeds up calculations // n-1 digits of accuracy. This dramatically speeds up calculations
// involving hundreds of digits or more. // involving hundreds of digits or more.
// The last part of this trim dealing with exponents never affects accuracy // The last part of this trim dealing with exponents never affects accuracy
// //
// RETURN: none, modifies the pointed to PRAT // RETURN: none, modifies the pointed to PRAT
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -680,7 +680,7 @@ void trimit( PRAT *px, int32_t precision)
{ {
if ( !g_ftrueinfinite ) if ( !g_ftrueinfinite )
{ {
long trim; long trim;
PNUMBER pp=(*px)->pp; PNUMBER pp=(*px)->pp;
PNUMBER pq=(*px)->pq; PNUMBER pq=(*px)->pq;

View file

@ -47,8 +47,8 @@ void scalerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32_t p
// EXPLANATION: This uses Taylor series // EXPLANATION: This uses Taylor series
// //
// n // n
// ___ 2j+1 // ___ 2j+1
// \ ] j X // \ ] j X
// \ -1 * --------- // \ -1 * ---------
// / (2j+1)! // / (2j+1)!
// /__] // /__]
@ -73,7 +73,7 @@ void _sinrat( PRAT *px, int32_t precision)
{ {
CREATETAYLOR(); CREATETAYLOR();
DUPRAT(pret,*px); DUPRAT(pret,*px);
DUPRAT(thisterm,*px); DUPRAT(thisterm,*px);
DUPNUM(n2,num_one); DUPNUM(n2,num_one);
@ -84,11 +84,11 @@ void _sinrat( PRAT *px, int32_t precision)
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) ); } while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
DESTROYTAYLOR(); DESTROYTAYLOR();
// Since *px might be epsilon above 1 or below -1, due to TRIMIT we need // Since *px might be epsilon above 1 or below -1, due to TRIMIT we need
// this trick here. // this trick here.
inbetween(px, rat_one, precision); inbetween(px, rat_one, precision);
// Since *px might be epsilon near zero we must set it to zero. // Since *px might be epsilon near zero we must set it to zero.
if ( rat_le(*px, rat_smallest, precision) && rat_ge(*px, rat_negsmallest, precision) ) if ( rat_le(*px, rat_smallest, precision) && rat_ge(*px, rat_negsmallest, precision) )
{ {
@ -166,13 +166,13 @@ void _cosrat( PRAT *px, uint32_t radix, int32_t precision)
CREATETAYLOR(); CREATETAYLOR();
destroynum(pret->pp); destroynum(pret->pp);
destroynum(pret->pq); destroynum(pret->pq);
pret->pp=longtonum( 1L, radix); pret->pp=longtonum( 1L, radix);
pret->pq=longtonum( 1L, radix); pret->pq=longtonum( 1L, radix);
DUPRAT(thisterm,pret) DUPRAT(thisterm,pret)
n2=longtonum(0L, radix); n2=longtonum(0L, radix);
xx->pp->sign *= -1; xx->pp->sign *= -1;
@ -181,7 +181,7 @@ void _cosrat( PRAT *px, uint32_t radix, int32_t precision)
} while ( !SMALL_ENOUGH_RAT( thisterm, precision) ); } while ( !SMALL_ENOUGH_RAT( thisterm, precision) );
DESTROYTAYLOR(); DESTROYTAYLOR();
// Since *px might be epsilon above 1 or below -1, due to TRIMIT we need // Since *px might be epsilon above 1 or below -1, due to TRIMIT we need
// this trick here. // this trick here.
inbetween(px, rat_one, precision); inbetween(px, rat_one, precision);
// Since *px might be epsilon near zero we must set it to zero. // Since *px might be epsilon near zero we must set it to zero.

View file

@ -80,7 +80,7 @@ void _sinhrat( PRAT *px, int32_t precision)
CREATETAYLOR(); CREATETAYLOR();
DUPRAT(pret,*px); DUPRAT(pret,*px);
DUPRAT(thisterm,pret); DUPRAT(thisterm,pret);
DUPNUM(n2,num_one); DUPNUM(n2,num_one);
@ -194,7 +194,7 @@ void coshrat( PRAT *px, uint32_t radix, int32_t precision)
{ {
_coshrat( px, radix, precision); _coshrat( px, radix, precision);
} }
// Since *px might be epsilon below 1 due to TRIMIT // Since *px might be epsilon below 1 due to TRIMIT
// we need this trick here. // we need this trick here.
if ( rat_lt(*px, rat_one, precision) ) if ( rat_lt(*px, rat_one, precision) )
{ {

View file

@ -46,7 +46,7 @@ UnitConverter::UnitConverter(_In_ const shared_ptr<IConverterDataLoader>& dataLo
{ {
m_dataLoader = dataLoader; m_dataLoader = dataLoader;
m_currencyDataLoader = currencyDataLoader; m_currencyDataLoader = currencyDataLoader;
//declaring the delimiter character conversion map // declaring the delimiter character conversion map
quoteConversions[L'|'] = L"{p}"; quoteConversions[L'|'] = L"{p}";
quoteConversions[L'['] = L"{lc}"; quoteConversions[L'['] = L"{lc}";
quoteConversions[L']'] = L"{rc}"; quoteConversions[L']'] = L"{rc}";
@ -90,7 +90,7 @@ vector<Category> UnitConverter::GetCategories()
} }
/// <summary> /// <summary>
/// Sets the current category in use by this converter, /// Sets the current category in use by this converter,
/// and returns a list of unit types that exist under the given category. /// and returns a list of unit types that exist under the given category.
/// </summary> /// </summary>
/// <param name="input">Category struct which we are setting</param> /// <param name="input">Category struct which we are setting</param>
@ -109,22 +109,8 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i
vector<Unit>& unitVector = m_categoryToUnits[m_currentCategory]; vector<Unit>& unitVector = m_categoryToUnits[m_currentCategory];
for (unsigned int i = 0; i < unitVector.size(); i++) for (unsigned int i = 0; i < unitVector.size(); i++)
{ {
if (unitVector[i].id == m_fromType.id) unitVector[i].isConversionSource = (unitVector[i].id == m_fromType.id);
{ unitVector[i].isConversionTarget = (unitVector[i].id == m_toType.id);
unitVector[i].isConversionSource = true;
}
else
{
unitVector[i].isConversionSource = false;
}
if (unitVector[i].id == m_toType.id)
{
unitVector[i].isConversionTarget = true;
}
else
{
unitVector[i].isConversionTarget = false;
}
} }
m_currentCategory = input; m_currentCategory = input;
if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-') if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-')
@ -156,21 +142,23 @@ Category UnitConverter::GetCurrentCategory()
/// <param name="toType">Unit struct we are converting to</param> /// <param name="toType">Unit struct we are converting to</param>
void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType)
{ {
if (CheckLoad()) if (!CheckLoad())
{ {
m_fromType = fromType; return;
m_toType = toType;
Calculate();
UpdateCurrencySymbols();
UpdateViewModel();
} }
m_fromType = fromType;
m_toType = toType;
Calculate();
UpdateCurrencySymbols();
UpdateViewModel();
} }
/// <summary> /// <summary>
/// Switches the active field, indicating that we are now entering data into /// Switches the active field, indicating that we are now entering data into
/// what was originally the return field, and storing results into what was /// what was originally the return field, and storing results into what was
/// originally the current field. We swap appropriate values, /// originally the current field. We swap appropriate values,
/// but do not callback, as values have not changed. /// but do not callback, as values have not changed.
/// </summary> /// </summary>
/// <param name="newValue"> /// <param name="newValue">
@ -181,22 +169,24 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType
/// </param> /// </param>
void UnitConverter::SwitchActive(const wstring& newValue) void UnitConverter::SwitchActive(const wstring& newValue)
{ {
if (CheckLoad()) if (!CheckLoad())
{ {
swap(m_fromType, m_toType); return;
swap(m_currentHasDecimal, m_returnHasDecimal); }
m_returnDisplay = m_currentDisplay;
m_currentDisplay = newValue;
m_currentHasDecimal = (m_currentDisplay.find(L'.') != m_currentDisplay.npos);
m_switchedActive = true;
if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr) swap(m_fromType, m_toType);
{ swap(m_currentHasDecimal, m_returnHasDecimal);
shared_ptr<ICurrencyConverterDataLoader> currencyDataLoader = GetCurrencyConverterDataLoader(); m_returnDisplay = m_currentDisplay;
const pair<wstring, wstring> currencyRatios = currencyDataLoader->GetCurrencyRatioEquality(m_fromType, m_toType); m_currentDisplay = newValue;
m_currentHasDecimal = (m_currentDisplay.find(L'.') != m_currentDisplay.npos);
m_switchedActive = true;
m_vmCurrencyCallback->CurrencyRatiosCallback(currencyRatios.first, currencyRatios.second); if (m_currencyDataLoader != nullptr && m_vmCurrencyCallback != nullptr)
} {
shared_ptr<ICurrencyConverterDataLoader> currencyDataLoader = GetCurrencyConverterDataLoader();
const pair<wstring, wstring> currencyRatios = currencyDataLoader->GetCurrencyRatioEquality(m_fromType, m_toType);
m_vmCurrencyCallback->CurrencyRatiosCallback(currencyRatios.first, currencyRatios.second);
} }
} }
@ -291,55 +281,53 @@ wstring UnitConverter::ConversionDataToString(ConversionData d, const wchar_t *
/// </summary> /// </summary>
wstring UnitConverter::Serialize() wstring UnitConverter::Serialize()
{ {
if (CheckLoad()) if (!CheckLoad())
{
wstringstream out(wstringstream::out);
const wchar_t * delimiter = L";";
out << UnitToString(m_fromType, delimiter) << "|";
out << UnitToString(m_toType, delimiter) << "|";
out << CategoryToString(m_currentCategory, delimiter) << "|";
out << std::to_wstring(m_currentHasDecimal) << delimiter << std::to_wstring(m_returnHasDecimal) << delimiter << std::to_wstring(m_switchedActive) << delimiter;
out << m_currentDisplay << delimiter << m_returnDisplay << delimiter << "|";
wstringstream categoryString(wstringstream::out);
wstringstream categoryToUnitString(wstringstream::out);
wstringstream unitToUnitToDoubleString(wstringstream::out);
for (const Category& c : m_categories)
{
categoryString << CategoryToString(c, delimiter) << ",";
}
for (const auto& cur : m_categoryToUnits)
{
categoryToUnitString << CategoryToString(cur.first, delimiter) << "[";
for (const Unit& u : cur.second)
{
categoryToUnitString << UnitToString(u, delimiter) << ",";
}
categoryToUnitString << "[" << "]";
}
for (const auto& cur : m_ratioMap)
{
unitToUnitToDoubleString << UnitToString(cur.first, delimiter) << "[";
for (const auto& curConversion : cur.second)
{
unitToUnitToDoubleString << UnitToString(curConversion.first, delimiter) << ":";
unitToUnitToDoubleString << ConversionDataToString(curConversion.second, delimiter) << ":,";
}
unitToUnitToDoubleString << "[" << "]";
}
out << categoryString.str() << "|";
out << categoryToUnitString.str() << "|";
out << unitToUnitToDoubleString.str() << "|";
wstring test = out.str();
return test;
}
else
{ {
return wstring(); return wstring();
} }
wstringstream out(wstringstream::out);
const wchar_t * delimiter = L";";
out << UnitToString(m_fromType, delimiter) << "|";
out << UnitToString(m_toType, delimiter) << "|";
out << CategoryToString(m_currentCategory, delimiter) << "|";
out << std::to_wstring(m_currentHasDecimal) << delimiter << std::to_wstring(m_returnHasDecimal) << delimiter << std::to_wstring(m_switchedActive) << delimiter;
out << m_currentDisplay << delimiter << m_returnDisplay << delimiter << "|";
wstringstream categoryString(wstringstream::out);
wstringstream categoryToUnitString(wstringstream::out);
wstringstream unitToUnitToDoubleString(wstringstream::out);
for (const Category& c : m_categories)
{
categoryString << CategoryToString(c, delimiter) << ",";
}
for (const auto& cur : m_categoryToUnits)
{
categoryToUnitString << CategoryToString(cur.first, delimiter) << "[";
for (const Unit& u : cur.second)
{
categoryToUnitString << UnitToString(u, delimiter) << ",";
}
categoryToUnitString << "[" << "]";
}
for (const auto& cur : m_ratioMap)
{
unitToUnitToDoubleString << UnitToString(cur.first, delimiter) << "[";
for (const auto& curConversion : cur.second)
{
unitToUnitToDoubleString << UnitToString(curConversion.first, delimiter) << ":";
unitToUnitToDoubleString << ConversionDataToString(curConversion.second, delimiter) << ":,";
}
unitToUnitToDoubleString << "[" << "]";
}
out << categoryString.str() << "|";
out << categoryToUnitString.str() << "|";
out << unitToUnitToDoubleString.str() << "|";
wstring test = out.str();
return test;
} }
/// <summary> /// <summary>
@ -349,55 +337,58 @@ wstring UnitConverter::Serialize()
void UnitConverter::DeSerialize(const wstring& serializedData) void UnitConverter::DeSerialize(const wstring& serializedData)
{ {
Reset(); Reset();
if (!serializedData.empty())
if (serializedData.empty())
{ {
vector<wstring> outerTokens = StringToVector(serializedData, L"|"); return;
assert(outerTokens.size() == EXPECTEDSERIALIZEDTOKENCOUNT);
m_fromType = StringToUnit(outerTokens[0]);
m_toType = StringToUnit(outerTokens[1]);
m_currentCategory = StringToCategory(outerTokens[2]);
vector<wstring> stateDataTokens = StringToVector(outerTokens[3], L";");
assert(stateDataTokens.size() == EXPECTEDSTATEDATATOKENCOUNT);
m_currentHasDecimal = (stateDataTokens[0].compare(L"1") == 0);
m_returnHasDecimal = (stateDataTokens[1].compare(L"1") == 0);
m_switchedActive = (stateDataTokens[2].compare(L"1") == 0);
m_currentDisplay = stateDataTokens[3];
m_returnDisplay = stateDataTokens[4];
vector<wstring> categoryListTokens = StringToVector(outerTokens[4], L",");
for (wstring token : categoryListTokens)
{
m_categories.push_back(StringToCategory(token));
}
vector<wstring> unitVectorTokens = StringToVector(outerTokens[5], L"]");
for (wstring unitVector : unitVectorTokens)
{
vector<wstring> mapcomponents = StringToVector(unitVector, L"[");
assert(mapcomponents.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Category key = StringToCategory(mapcomponents[0]);
vector<wstring> units = StringToVector(mapcomponents[1], L",");
for (wstring unit : units)
{
m_categoryToUnits[key].push_back(StringToUnit(unit));
}
}
vector<wstring> ratioMapTokens = StringToVector(outerTokens[6], L"]");
for (wstring token : ratioMapTokens)
{
vector<wstring> ratioMapComponentTokens = StringToVector(token, L"[");
assert(ratioMapComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit key = StringToUnit(ratioMapComponentTokens[0]);
vector<wstring> ratioMapList = StringToVector(ratioMapComponentTokens[1], L",");
for (wstring subtoken : ratioMapList)
{
vector<wstring> ratioMapSubComponentTokens = StringToVector(subtoken, L":");
assert(ratioMapSubComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit subkey = StringToUnit(ratioMapSubComponentTokens[0]);
ConversionData conversion = StringToConversionData(ratioMapSubComponentTokens[1]);
m_ratioMap[key][subkey] = conversion;
}
}
UpdateViewModel();
} }
vector<wstring> outerTokens = StringToVector(serializedData, L"|");
assert(outerTokens.size() == EXPECTEDSERIALIZEDTOKENCOUNT);
m_fromType = StringToUnit(outerTokens[0]);
m_toType = StringToUnit(outerTokens[1]);
m_currentCategory = StringToCategory(outerTokens[2]);
vector<wstring> stateDataTokens = StringToVector(outerTokens[3], L";");
assert(stateDataTokens.size() == EXPECTEDSTATEDATATOKENCOUNT);
m_currentHasDecimal = (stateDataTokens[0].compare(L"1") == 0);
m_returnHasDecimal = (stateDataTokens[1].compare(L"1") == 0);
m_switchedActive = (stateDataTokens[2].compare(L"1") == 0);
m_currentDisplay = stateDataTokens[3];
m_returnDisplay = stateDataTokens[4];
vector<wstring> categoryListTokens = StringToVector(outerTokens[4], L",");
for (wstring token : categoryListTokens)
{
m_categories.push_back(StringToCategory(token));
}
vector<wstring> unitVectorTokens = StringToVector(outerTokens[5], L"]");
for (wstring unitVector : unitVectorTokens)
{
vector<wstring> mapcomponents = StringToVector(unitVector, L"[");
assert(mapcomponents.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Category key = StringToCategory(mapcomponents[0]);
vector<wstring> units = StringToVector(mapcomponents[1], L",");
for (wstring unit : units)
{
m_categoryToUnits[key].push_back(StringToUnit(unit));
}
}
vector<wstring> ratioMapTokens = StringToVector(outerTokens[6], L"]");
for (wstring token : ratioMapTokens)
{
vector<wstring> ratioMapComponentTokens = StringToVector(token, L"[");
assert(ratioMapComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit key = StringToUnit(ratioMapComponentTokens[0]);
vector<wstring> ratioMapList = StringToVector(ratioMapComponentTokens[1], L",");
for (wstring subtoken : ratioMapList)
{
vector<wstring> ratioMapSubComponentTokens = StringToVector(subtoken, L":");
assert(ratioMapSubComponentTokens.size() == EXPECTEDMAPCOMPONENTTOKENCOUNT);
Unit subkey = StringToUnit(ratioMapSubComponentTokens[0]);
ConversionData conversion = StringToConversionData(ratioMapSubComponentTokens[1]);
m_ratioMap[key][subkey] = conversion;
}
}
UpdateViewModel();
} }
/// <summary> /// <summary>
@ -406,21 +397,23 @@ void UnitConverter::DeSerialize(const wstring& serializedData)
/// <param name="userPreferences">wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it</param> /// <param name="userPreferences">wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it</param>
void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) void UnitConverter::RestoreUserPreferences(const wstring& userPreferences)
{ {
if (!userPreferences.empty()) if (userPreferences.empty())
{ {
vector<wstring> outerTokens = StringToVector(userPreferences, L"|"); return;
if (outerTokens.size() == 3) }
{
m_fromType = StringToUnit(outerTokens[0]); vector<wstring> outerTokens = StringToVector(userPreferences, L"|");
m_toType = StringToUnit(outerTokens[1]); if (outerTokens.size() == 3)
m_currentCategory = StringToCategory(outerTokens[2]); {
} m_fromType = StringToUnit(outerTokens[0]);
m_toType = StringToUnit(outerTokens[1]);
m_currentCategory = StringToCategory(outerTokens[2]);
} }
} }
/// <summary> /// <summary>
/// Serializes the Category and Associated Units in the converter and returns it as a string /// Serializes the Category and Associated Units in the converter and returns it as a string
/// </summary> /// </summary>
wstring UnitConverter::SaveUserPreferences() wstring UnitConverter::SaveUserPreferences()
{ {
wstringstream out(wstringstream::out); wstringstream out(wstringstream::out);
@ -441,7 +434,7 @@ wstring UnitConverter::Quote(const wstring& s)
{ {
wstringstream quotedString(wstringstream::out); wstringstream quotedString(wstringstream::out);
//Iterate over the delimiter characters we need to quote // Iterate over the delimiter characters we need to quote
wstring::const_iterator cursor = s.begin(); wstring::const_iterator cursor = s.begin();
while(cursor != s.end()) while(cursor != s.end())
{ {
@ -479,7 +472,7 @@ wstring UnitConverter::Unquote(const wstring& s)
} }
if (cursor == s.end()) if (cursor == s.end())
{ {
//badly formatted // Badly formatted
break; break;
} }
else else
@ -503,144 +496,146 @@ wstring UnitConverter::Unquote(const wstring& s)
/// <param name="command">Command enum representing the command that was entered</param> /// <param name="command">Command enum representing the command that was entered</param>
void UnitConverter::SendCommand(Command command) void UnitConverter::SendCommand(Command command)
{ {
if (CheckLoad()) if (!CheckLoad())
{ {
//TODO: Localization of characters return;
bool clearFront = false; }
if (m_currentDisplay == L"0")
// TODO: Localization of characters
bool clearFront = false;
if (m_currentDisplay == L"0")
{
clearFront = true;
}
bool clearBack = false;
if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED))
{
clearBack = true;
}
if (command != Command::Negate && m_switchedActive)
{
ClearValues();
m_switchedActive = false;
clearFront = true;
clearBack = false;
}
switch (command)
{
case Command::Zero:
m_currentDisplay += L"0";
break;
case Command::One:
m_currentDisplay += L"1";
break;
case Command::Two:
m_currentDisplay += L"2";
break;
case Command::Three:
m_currentDisplay += L"3";
break;
case Command::Four:
m_currentDisplay += L"4";
break;
case Command::Five:
m_currentDisplay += L"5";
break;
case Command::Six:
m_currentDisplay += L"6";
break;
case Command::Seven:
m_currentDisplay += L"7";
break;
case Command::Eight:
m_currentDisplay += L"8";
break;
case Command::Nine:
m_currentDisplay += L"9";
break;
case Command::Decimal:
clearFront = false;
clearBack = false;
if (!m_currentHasDecimal)
{ {
clearFront = true; m_currentDisplay += L".";
m_currentHasDecimal = true;
} }
bool clearBack = false; break;
if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED))
case Command::Backspace:
clearFront = false;
clearBack = false;
if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2)
{ {
clearBack = true; if (m_currentDisplay.back() == '.')
}
if (command != Command::Negate && m_switchedActive)
{
ClearValues();
m_switchedActive = false;
clearFront = true;
clearBack = false;
}
switch (command)
{
case Command::Zero:
m_currentDisplay += L"0";
break;
case Command::One:
m_currentDisplay += L"1";
break;
case Command::Two:
m_currentDisplay += L"2";
break;
case Command::Three:
m_currentDisplay += L"3";
break;
case Command::Four:
m_currentDisplay += L"4";
break;
case Command::Five:
m_currentDisplay += L"5";
break;
case Command::Six:
m_currentDisplay += L"6";
break;
case Command::Seven:
m_currentDisplay += L"7";
break;
case Command::Eight:
m_currentDisplay += L"8";
break;
case Command::Nine:
m_currentDisplay += L"9";
break;
case Command::Decimal:
clearFront = false;
clearBack = false;
if (!m_currentHasDecimal)
{ {
m_currentDisplay += L"."; m_currentHasDecimal = false;
m_currentHasDecimal = true;
} }
break; m_currentDisplay.pop_back();
}
else
{
m_currentDisplay = L"0";
m_currentHasDecimal = false;
}
break;
case Command::Backspace: case Command::Negate:
clearFront = false; clearFront = false;
clearBack = false; clearBack = false;
if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) if (m_currentCategory.supportsNegative)
{
if (m_currentDisplay.front() == '-')
{ {
if (m_currentDisplay.back() == '.') m_currentDisplay.erase(0, 1);
{
m_currentHasDecimal = false;
}
m_currentDisplay.pop_back();
} }
else else
{ {
m_currentDisplay = L"0"; m_currentDisplay.insert(0, 1, '-');
m_currentHasDecimal = false;
} }
break;
case Command::Negate:
clearFront = false;
clearBack = false;
if (m_currentCategory.supportsNegative)
{
if (m_currentDisplay.front() == '-')
{
m_currentDisplay.erase(0, 1);
}
else
{
m_currentDisplay.insert(0, 1, '-');
}
}
break;
case Command::Clear:
clearFront = false;
clearBack = false;
ClearValues();
break;
case Command::Reset:
clearFront = false;
clearBack = false;
ClearValues();
Reset();
break;
default:
break;
} }
break;
if (clearFront) case Command::Clear:
{ clearFront = false;
m_currentDisplay.erase(0, 1); clearBack = false;
} ClearValues();
if (clearBack) break;
{
m_currentDisplay.erase(m_currentDisplay.size() - 1, 1);
m_vmCallback->MaxDigitsReached();
}
Calculate(); case Command::Reset:
clearFront = false;
clearBack = false;
ClearValues();
Reset();
break;
UpdateViewModel(); default:
break;
} }
if (clearFront)
{
m_currentDisplay.erase(0, 1);
}
if (clearBack)
{
m_currentDisplay.erase(m_currentDisplay.size() - 1, 1);
m_vmCallback->MaxDigitsReached();
}
Calculate();
UpdateViewModel();
} }
/// <summary> /// <summary>
@ -728,7 +723,7 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
vector<SuggestedValueIntermediate> intermediateVector; vector<SuggestedValueIntermediate> intermediateVector;
vector<SuggestedValueIntermediate> intermediateWhimsicalVector; vector<SuggestedValueIntermediate> intermediateWhimsicalVector;
unordered_map<Unit, ConversionData, UnitHash> ratios = m_ratioMap[m_fromType]; unordered_map<Unit, ConversionData, UnitHash> ratios = m_ratioMap[m_fromType];
//Calculate converted values for every other unit type in this category, along with their magnitude // Calculate converted values for every other unit type in this category, along with their magnitude
for (const auto& cur : ratios) for (const auto& cur : ratios)
{ {
if (cur.first != m_fromType && cur.first != m_toType) if (cur.first != m_fromType && cur.first != m_toType)
@ -745,21 +740,21 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
} }
} }
//Sort the resulting list by absolute magnitude, breaking ties by choosing the positive value // Sort the resulting list by absolute magnitude, breaking ties by choosing the positive value
sort(intermediateVector.begin(), intermediateVector.end(), [] sort(intermediateVector.begin(), intermediateVector.end(), []
(SuggestedValueIntermediate first, SuggestedValueIntermediate second) (SuggestedValueIntermediate first, SuggestedValueIntermediate second)
{ {
if (abs(first.magnitude) == abs(second.magnitude)) if (abs(first.magnitude) == abs(second.magnitude))
{ {
return first.magnitude > second.magnitude; return first.magnitude > second.magnitude;
} }
else else
{ {
return abs(first.magnitude) < abs(second.magnitude); return abs(first.magnitude) < abs(second.magnitude);
} }
}); });
//Now that the list is sorted, iterate over it and populate the return vector with properly rounded and formatted return strings // Now that the list is sorted, iterate over it and populate the return vector with properly rounded and formatted return strings
for (const auto& entry : intermediateVector) for (const auto& entry : intermediateVector)
{ {
wstring roundedString; wstring roundedString;
@ -783,7 +778,7 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
} }
// The Whimsicals are determined differently // The Whimsicals are determined differently
//Sort the resulting list by absolute magnitude, breaking ties by choosing the positive value // Sort the resulting list by absolute magnitude, breaking ties by choosing the positive value
sort(intermediateWhimsicalVector.begin(), intermediateWhimsicalVector.end(), [] sort(intermediateWhimsicalVector.begin(), intermediateWhimsicalVector.end(), []
(SuggestedValueIntermediate first, SuggestedValueIntermediate second) (SuggestedValueIntermediate first, SuggestedValueIntermediate second)
{ {
@ -797,7 +792,7 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
} }
}); });
//Now that the list is sorted, iterate over it and populate the return vector with properly rounded and formatted return strings // Now that the list is sorted, iterate over it and populate the return vector with properly rounded and formatted return strings
vector<tuple<wstring, Unit>> whimsicalReturnVector; vector<tuple<wstring, Unit>> whimsicalReturnVector;
for (const auto& entry : intermediateWhimsicalVector) for (const auto& entry : intermediateWhimsicalVector)
@ -844,47 +839,49 @@ void UnitConverter::Reset()
ClearValues(); ClearValues();
m_switchedActive = false; m_switchedActive = false;
if (!m_categories.empty()) if (m_categories.empty())
{ {
m_currentCategory = m_categories[0]; return;
}
m_categoryToUnits.clear(); m_currentCategory = m_categories[0];
m_ratioMap.clear();
bool readyCategoryFound = false; m_categoryToUnits.clear();
for (const Category& category : m_categories) m_ratioMap.clear();
bool readyCategoryFound = false;
for (const Category& category : m_categories)
{
shared_ptr<IConverterDataLoader> activeDataLoader = GetDataLoaderForCategory(category);
if (activeDataLoader == nullptr)
{ {
shared_ptr<IConverterDataLoader> activeDataLoader = GetDataLoaderForCategory(category); // The data loader is different depending on the category, e.g. currency data loader
if (activeDataLoader == nullptr) // is different from the static data loader.
{ // If there is no data loader for this category, continue.
// The data loader is different depending on the category, e.g. currency data loader continue;
// is different from the static data loader.
// If there is no data loader for this category, continue.
continue;
}
vector<Unit> units = activeDataLoader->LoadOrderedUnits(category);
m_categoryToUnits[category] = units;
// Just because the units are empty, doesn't mean the user can't select this category,
// we just want to make sure we don't let an unready category be the default.
if (!units.empty())
{
for (Unit u : units)
{
m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u);
}
if (!readyCategoryFound)
{
m_currentCategory = category;
readyCategoryFound = true;
}
}
} }
InitializeSelectedUnits(); vector<Unit> units = activeDataLoader->LoadOrderedUnits(category);
Calculate(); m_categoryToUnits[category] = units;
// Just because the units are empty, doesn't mean the user can't select this category,
// we just want to make sure we don't let an unready category be the default.
if (!units.empty())
{
for (Unit u : units)
{
m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u);
}
if (!readyCategoryFound)
{
m_currentCategory = category;
readyCategoryFound = true;
}
}
} }
InitializeSelectedUnits();
Calculate();
} }
/// <summary> /// <summary>
@ -1029,22 +1026,24 @@ void UnitConverter::Calculate()
/// <param name="input">wstring to trim</param> /// <param name="input">wstring to trim</param>
void UnitConverter::TrimString(wstring& returnString) void UnitConverter::TrimString(wstring& returnString)
{ {
if (returnString.find(L'.') != m_returnDisplay.npos) if (returnString.find(L'.') == m_returnDisplay.npos)
{ {
wstring::iterator iter; return;
for (iter = returnString.end() - 1; ;iter--) }
wstring::iterator iter;
for (iter = returnString.end() - 1; ;iter--)
{
if (*iter != L'0')
{ {
if (*iter != L'0') returnString.erase(iter + 1, returnString.end());
{ break;
returnString.erase(iter + 1, returnString.end());
break;
}
}
if (*(returnString.end()-1) == L'.')
{
returnString.erase(returnString.end()-1, returnString.end());
} }
} }
if (*(returnString.end()-1) == L'.')
{
returnString.erase(returnString.end()-1, returnString.end());
}
} }
/// <summary> /// <summary>

View file

@ -51,7 +51,7 @@ namespace UnitConversionManager
// null checks. // null checks.
// //
// unitId, name, abbreviation, isConversionSource, isConversionTarget, isWhimsical // unitId, name, abbreviation, isConversionSource, isConversionTarget, isWhimsical
const Unit EMPTY_UNIT = Unit{ -1, L"", L"", true, true, false }; inline const Unit EMPTY_UNIT = Unit{ -1, L"", L"", true, true, false };
struct Category struct Category
{ {

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#pragma once #pragma once
@ -7,11 +7,16 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
// Windows headers define min/max macros.
// Disable it for project code.
#define NOMINMAX
#include <assert.h> #include <assert.h>
#include <windows.h> #include <windows.h>
#include <winerror.h> #include <winerror.h>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <iterator>
#include <string> #include <string>
#include <memory> #include <memory>
#include <vector> #include <vector>

View file

@ -32,14 +32,11 @@ using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Media;
namespace CalculatorApp::ViewModel::ApplicationViewModelProperties namespace
{ {
StringReference Mode(L"Mode"); StringReference CategoriesPropertyName(L"Categories");
StringReference PreviousMode(L"PreviousMode"); StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility");
StringReference ClearMemoryVisibility(L"ClearMemoryVisibility"); StringReference AppBarVisibilityPropertyName(L"AppBarVisibility");
StringReference AppBarVisibility(L"AppBarVisibility");
StringReference CategoryName(L"CategoryName");
StringReference Categories(L"Categories");
} }
ApplicationViewModel::ApplicationViewModel() : ApplicationViewModel::ApplicationViewModel() :
@ -60,7 +57,7 @@ void ApplicationViewModel::Mode::set(ViewMode value)
PreviousMode = m_mode; PreviousMode = m_mode;
m_mode = value; m_mode = value;
OnModeChanged(); OnModeChanged();
RaisePropertyChanged(ApplicationViewModelProperties::Mode); RaisePropertyChanged(ModePropertyName);
} }
} }
@ -69,7 +66,7 @@ void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup^>^
if (m_categories != value) if (m_categories != value)
{ {
m_categories = value; m_categories = value;
RaisePropertyChanged(ApplicationViewModelProperties::Categories); RaisePropertyChanged(CategoriesPropertyName);
} }
} }
@ -163,11 +160,11 @@ void ApplicationViewModel::OnModeChanged()
// //
// Save the changed mode, so that the new window launches in this mode. // 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. // 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(ApplicationViewModelProperties::Mode, NavCategory::Serialize(m_mode)); ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategory::Serialize(m_mode));
TraceLogger::GetInstance().LogModeChangeEnd(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); TraceLogger::GetInstance().LogModeChangeEnd(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
RaisePropertyChanged(ApplicationViewModelProperties::ClearMemoryVisibility); RaisePropertyChanged(ClearMemoryVisibilityPropertyName);
RaisePropertyChanged(ApplicationViewModelProperties::AppBarVisibility); RaisePropertyChanged(AppBarVisibilityPropertyName);
} }
void ApplicationViewModel::OnCopyCommand(Object^ parameter) void ApplicationViewModel::OnCopyCommand(Object^ parameter)

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#pragma once #pragma once
@ -11,16 +11,6 @@ namespace CalculatorApp
{ {
namespace ViewModel namespace ViewModel
{ {
namespace ApplicationViewModelProperties
{
extern Platform::StringReference Mode;
extern Platform::StringReference PreviousMode;
extern Platform::StringReference ClearMemoryVisibility;
extern Platform::StringReference AppBarVisibility;
extern Platform::StringReference CategoryName;
extern Platform::StringReference Categories;
}
[Windows::UI::Xaml::Data::Bindable] [Windows::UI::Xaml::Data::Bindable]
public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{ {
@ -32,9 +22,9 @@ namespace CalculatorApp
OBSERVABLE_OBJECT(); OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel^, CalculatorViewModel); OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel^, CalculatorViewModel);
OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel^, DateCalcViewModel); OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel^, DateCalcViewModel);
OBSERVABLE_PROPERTY_RW(CalculatorApp::ViewModel::UnitConverterViewModel^, ConverterViewModel); OBSERVABLE_PROPERTY_RW(UnitConverterViewModel^, ConverterViewModel);
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode); OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode);
OBSERVABLE_PROPERTY_RW(Platform::String^, CategoryName); OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, CategoryName);
COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand); COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand);
COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand); COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand);
@ -48,6 +38,13 @@ namespace CalculatorApp
void set(CalculatorApp::Common::ViewMode value); 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 property Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ Categories
{ {

View file

@ -3,9 +3,9 @@
#pragma once #pragma once
namespace CalculatorApp { namespace Common namespace CalculatorApp { namespace Common
{ {
ref class AlwaysSelectedCollectionView sealed: ref class AlwaysSelectedCollectionView sealed:
public Windows::UI::Xaml::DependencyObject, public Windows::UI::Xaml::DependencyObject,
public Windows::UI::Xaml::Data::ICollectionView public Windows::UI::Xaml::Data::ICollectionView
{ {
@ -14,11 +14,11 @@ namespace CalculatorApp { namespace Common
m_currentPosition(-1) m_currentPosition(-1)
{ {
m_source = source; m_source = source;
Windows::UI::Xaml::Interop::IBindableObservableVector^ observable = dynamic_cast<Windows::UI::Xaml::Interop::IBindableObservableVector^>(source); Windows::UI::Xaml::Interop::IBindableObservableVector^ observable = dynamic_cast<Windows::UI::Xaml::Interop::IBindableObservableVector^>(source);
if (observable) if (observable)
{ {
observable->VectorChanged += observable->VectorChanged +=
ref new Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler(this, &AlwaysSelectedCollectionView::OnSourceBindableVectorChanged); ref new Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler(this, &AlwaysSelectedCollectionView::OnSourceBindableVectorChanged);
} }
} }
@ -53,7 +53,7 @@ namespace CalculatorApp { namespace Common
return ref new Platform::Collections::Vector<Platform::Object^>(); return ref new Platform::Collections::Vector<Platform::Object^>();
} }
} }
property bool HasMoreItems property bool HasMoreItems
{ {
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::HasMoreItems::get virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::HasMoreItems::get
{ {
@ -77,7 +77,7 @@ namespace CalculatorApp { namespace Common
} }
// The item is not in the collection // The item is not in the collection
// We're going to schedule a call back later so we // We're going to schedule a call back later so we
// restore the selection to the way we wanted it to begin with // restore the selection to the way we wanted it to begin with
if (m_currentPosition >= 0 && m_currentPosition < static_cast<int>(m_source->Size)) if (m_currentPosition >= 0 && m_currentPosition < static_cast<int>(m_source->Size))
{ {
@ -161,7 +161,7 @@ namespace CalculatorApp { namespace Common
m_currentChanging -= token; m_currentChanging -= token;
} }
} }
// IVector<Object^> // IVector<Object^>
// Not implemented methods // Not implemented methods
virtual void Append(Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::Append virtual void Append(Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::Append
@ -219,7 +219,7 @@ namespace CalculatorApp { namespace Common
return m_source->Size; return m_source->Size;
} }
} }
// IObservableVector<Object^> // IObservableVector<Object^>
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ VectorChanged event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ VectorChanged
{ {
@ -262,9 +262,9 @@ namespace CalculatorApp { namespace Common
private: private:
virtual Platform::Object^ Convert( virtual Platform::Object^ Convert(
Platform::Object^ value, Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/, Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/, Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{ {
auto result = dynamic_cast<Windows::UI::Xaml::Interop::IBindableVector^>(value); auto result = dynamic_cast<Windows::UI::Xaml::Interop::IBindableVector^>(value);
@ -276,9 +276,9 @@ namespace CalculatorApp { namespace Common
} }
virtual Platform::Object^ ConvertBack( virtual Platform::Object^ ConvertBack(
Platform::Object^ /*value*/, Platform::Object^ /*value*/,
Windows::UI::Xaml::Interop::TypeName /*targetType*/, Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/, Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{ {
return Windows::UI::Xaml::DependencyProperty::UnsetValue; return Windows::UI::Xaml::DependencyProperty::UnsetValue;

View file

@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#pragma once
#include "pch.h" #include "pch.h"
#include "AppResourceProvider.h" #include "AppResourceProvider.h"

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "pch.h" #include "pch.h"
@ -20,6 +20,8 @@ namespace CalculatorApp::Common::Automation
StringReference CategoryNameChanged(L"CategoryNameChanged"); StringReference CategoryNameChanged(L"CategoryNameChanged");
StringReference UpdateCurrencyRates(L"UpdateCurrencyRates"); StringReference UpdateCurrencyRates(L"UpdateCurrencyRates");
StringReference DisplayCopied(L"DisplayCopied"); StringReference DisplayCopied(L"DisplayCopied");
StringReference OpenParenthesisCountChanged(L"OpenParenthesisCountChanged");
StringReference NoParenthesisAdded(L"NoParenthesisAdded");
} }
} }
@ -142,3 +144,21 @@ NarratorAnnouncement^ CalculatorAnnouncement::GetDisplayCopiedAnnouncement(Strin
AutomationNotificationKind::ActionCompleted, AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent); AutomationNotificationProcessing::ImportantMostRecent);
} }
NarratorAnnouncement^ CalculatorAnnouncement::GetOpenParenthesisCountChangedAnnouncement(String^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::OpenParenthesisCountChanged,
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement^ CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(String^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::NoParenthesisAdded,
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#pragma once #pragma once
@ -88,7 +88,10 @@ namespace CalculatorApp::Common::Automation
static NarratorAnnouncement^ GetCategoryNameChangedAnnouncement(Platform::String^ announcement); static NarratorAnnouncement^ GetCategoryNameChangedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetUpdateCurrencyRatesAnnouncement(Platform::String^ announcement); static NarratorAnnouncement^ GetUpdateCurrencyRatesAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetDisplayCopiedAnnouncement(Platform::String^ announcement); static NarratorAnnouncement^ GetDisplayCopiedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetOpenParenthesisCountChangedAnnouncement(Platform::String^ announcement);
static NarratorAnnouncement^ GetNoRightParenthesisAddedAnnouncement(Platform::String ^ announcement);
}; };
} }

View file

@ -18,17 +18,17 @@ void BindableBase::OnPropertyChanged(String^ propertyName)
PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName)); PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName));
} }
Windows::UI::Xaml::Data::ICustomProperty^ BindableBase::GetCustomProperty(Platform::String^ name) Windows::UI::Xaml::Data::ICustomProperty^ BindableBase::GetCustomProperty(Platform::String^ name)
{ {
return nullptr; return nullptr;
} }
Windows::UI::Xaml::Data::ICustomProperty^ BindableBase::GetIndexedProperty(Platform::String^ name, Windows::UI::Xaml::Interop::TypeName type) Windows::UI::Xaml::Data::ICustomProperty^ BindableBase::GetIndexedProperty(Platform::String^ name, Windows::UI::Xaml::Interop::TypeName type)
{ {
return nullptr; return nullptr;
} }
Platform::String^ BindableBase::GetStringRepresentation() Platform::String^ BindableBase::GetStringRepresentation()
{ {
return this->ToString(); return this->ToString();
} }

View file

@ -80,7 +80,7 @@ namespace CalculatorApp
D = (int) CM::Command::CommandD, D = (int) CM::Command::CommandD,
E = (int) CM::Command::CommandE, E = (int) CM::Command::CommandE,
F = (int) CM::Command::CommandF, F = (int) CM::Command::CommandF,
Memory, // This is the memory button. Doesn't have a direct mapping to the CalcEngine. Memory, // This is the memory button. Doesn't have a direct mapping to the CalcEngine.
Sinh = (int) CM::Command::CommandSINH, Sinh = (int) CM::Command::CommandSINH,
Cosh = (int) CM::Command::CommandCOSH, Cosh = (int) CM::Command::CommandCOSH,
Tanh = (int) CM::Command::CommandTANH, Tanh = (int) CM::Command::CommandTANH,

View file

@ -2,7 +2,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
// This class provides the concrete implementation for the ICalcDisplay interface // This class provides the concrete implementation for the ICalcDisplay interface
// that is declared in the Calculation Manager Library. // that is declared in the Calculation Manager Library.
#include "pch.h" #include "pch.h"
#include "CalculatorDisplay.h" #include "CalculatorDisplay.h"
#include "StandardCalculatorViewModel.h" #include "StandardCalculatorViewModel.h"
@ -29,8 +29,7 @@ void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue
{ {
if (m_callbackReference) if (m_callbackReference)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->SetPrimaryDisplay(displayStringValue, isError); calcVM->SetPrimaryDisplay(displayStringValue, isError);
} }
@ -41,20 +40,29 @@ void CalculatorDisplay::SetParenDisplayText(_In_ const std::wstring& parenthesis
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->SetParenthesisCount(parenthesisCount); 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) void CalculatorDisplay::SetIsInError(bool isError)
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->IsInError = isError; calcVM->IsInError = isError;
} }
@ -65,8 +73,7 @@ void CalculatorDisplay::SetExpressionDisplay(_Inout_ std::shared_ptr<CalculatorV
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if(auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->SetExpressionDisplay(tokens, commands); calcVM->SetExpressionDisplay(tokens, commands);
} }
@ -77,8 +84,7 @@ void CalculatorDisplay::SetMemorizedNumbers(_In_ const vector<std::wstring>& new
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->SetMemorizedNumbers(newMemorizedNumbers); calcVM->SetMemorizedNumbers(newMemorizedNumbers);
} }
@ -89,8 +95,7 @@ void CalculatorDisplay::OnHistoryItemAdded(_In_ unsigned int addedItemIndex)
{ {
if (m_historyCallbackReference != nullptr) if (m_historyCallbackReference != nullptr)
{ {
auto historyVM = m_historyCallbackReference.Resolve<ViewModel::HistoryViewModel>(); if (auto historyVM = m_historyCallbackReference.Resolve<ViewModel::HistoryViewModel>())
if (historyVM)
{ {
historyVM->OnHistoryItemAdded(addedItemIndex); historyVM->OnHistoryItemAdded(addedItemIndex);
} }
@ -101,8 +106,7 @@ void CalculatorDisplay::MaxDigitsReached()
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->OnMaxDigitsReached(); calcVM->OnMaxDigitsReached();
} }
@ -113,8 +117,7 @@ void CalculatorDisplay::BinaryOperatorReceived()
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->OnBinaryOperatorReceived(); calcVM->OnBinaryOperatorReceived();
} }
@ -125,8 +128,7 @@ void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory)
{ {
if (m_callbackReference != nullptr) if (m_callbackReference != nullptr)
{ {
auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>(); if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
if (calcVM)
{ {
calcVM->OnMemoryItemChanged(indexOfMemory); calcVM->OnMemoryItemChanged(indexOfMemory);
} }

View file

@ -22,6 +22,7 @@ namespace CalculatorApp
void SetMemorizedNumbers(_In_ const std::vector<std::wstring>& memorizedNumbers) override; void SetMemorizedNumbers(_In_ const std::vector<std::wstring>& memorizedNumbers) override;
void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override;
void SetParenDisplayText(_In_ const std::wstring& parenthesisCount) override; void SetParenDisplayText(_In_ const std::wstring& parenthesisCount) override;
void OnNoRightParenAdded() override;
void MaxDigitsReached() override; void MaxDigitsReached() override;
void BinaryOperatorReceived() override; void BinaryOperatorReceived() override;
void MemoryItemChanged(unsigned int indexOfMemory) override; void MemoryItemChanged(unsigned int indexOfMemory) override;

View file

@ -12,7 +12,7 @@ namespace CalculatorApp
public: public:
ConversionResultTaskHelper(unsigned int delay, const std::function<void()> functionToRun); ConversionResultTaskHelper(unsigned int delay, const std::function<void()> functionToRun);
~ConversionResultTaskHelper(); ~ConversionResultTaskHelper();
private: private:
concurrency::task<void> CompleteAfter(unsigned int timeout); concurrency::task<void> CompleteAfter(unsigned int timeout);

View file

@ -26,6 +26,7 @@ constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" };
// [\s\x85] means white-space characters // [\s\x85] means white-space characters
static const wstring c_wspc = L"[\\s\\x85]*"; static const wstring c_wspc = L"[\\s\\x85]*";
static const wstring c_wspcLParens = c_wspc + L"[(]*" + c_wspc; 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_wspcRParens = c_wspc + L"[)]*" + c_wspc;
static const wstring c_signedDecFloat = L"[-+]?\\d*(\\d|[.])\\d*"; static const wstring c_signedDecFloat = L"[-+]?\\d*(\\d|[.])\\d*";
@ -44,8 +45,8 @@ static const array<wregex, 1> standardModePatterns =
}; };
static const array<wregex, 2> scientificModePatterns = static const array<wregex, 2> scientificModePatterns =
{ {
wregex(c_wspcLParens + c_signedDecFloat + c_wspcRParens), wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_wspcRParens),
wregex(c_wspcLParens + c_signedDecFloat + L"[e]([+]|[-])+\\d+" + 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 = static const array<array<wregex, 5>, 4> programmerModePatterns =
{ { { {
@ -129,17 +130,17 @@ String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode m
if (pastedText->Length() > MaxPasteableLength) if (pastedText->Length() > MaxPasteableLength)
{ {
// return NoOp to indicate don't paste anything. // return NoOp to indicate don't paste anything.
TraceLogger::GetInstance().LogInvalidInputPasted(L"PastedExpressionSizeGreaterThanMaxAllowed", L"MoreThanMaxInput", mode, programmerNumberBase, bitLengthType); TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"PastedExpressionSizeGreaterThanMaxAllowed", mode, programmerNumberBase, bitLengthType);
return StringReference(PasteErrorString); return StringReference(PasteErrorString);
} }
wstring pasteExpression = pastedText->Data(); wstring pasteExpression = pastedText->Data();
// Get english translated expression // Get english translated expression
String^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression); String^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression);
// Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333 // Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333
pasteExpression = Utils::RemoveUnwantedCharsFromWstring(englishString->Data()); pasteExpression = RemoveUnwantedCharsFromWstring(englishString->Data());
// If the last character is an = sign, remove it from the pasteExpression to allow evaluating the result on paste. // 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'=') if (!pasteExpression.empty() && pasteExpression.back() == L'=')
@ -164,7 +165,7 @@ String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode m
// validate each operand with patterns for different modes // validate each operand with patterns for different modes
if (!ExpressionRegExMatch(operands, mode, modeType, programmerNumberBase, bitLengthType)) if (!ExpressionRegExMatch(operands, mode, modeType, programmerNumberBase, bitLengthType))
{ {
TraceLogger::GetInstance().LogInvalidInputPasted(L"InvalidExpressionForPresentMode", pastedText->Data(), mode, programmerNumberBase, bitLengthType); TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"InvalidExpressionForPresentMode", mode, programmerNumberBase, bitLengthType);
return StringReference(PasteErrorString); return StringReference(PasteErrorString);
} }
@ -193,7 +194,7 @@ vector<wstring> CopyPasteManager::ExtractOperands(const wstring& pasteExpression
if (operands.size() >= MaxOperandCount) if (operands.size() >= MaxOperandCount)
{ {
TraceLogger::GetInstance().LogInvalidInputPasted(L"OperandCountGreaterThanMaxCount", pasteExpression.c_str(), mode, programmerNumberBase, bitLengthType); TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"OperandCountGreaterThanMaxCount", mode, programmerNumberBase, bitLengthType);
operands.clear(); operands.clear();
return operands; return operands;
} }
@ -207,7 +208,7 @@ vector<wstring> CopyPasteManager::ExtractOperands(const wstring& pasteExpression
// to disallow pasting of 1e+12345 as 1e+1234, max exponent that can be pasted is 9999. // to disallow pasting of 1e+12345 as 1e+1234, max exponent that can be pasted is 9999.
if (expLength > MaxExponentLength) if (expLength > MaxExponentLength)
{ {
TraceLogger::GetInstance().LogInvalidInputPasted(L"ExponentLengthGreaterThanMaxLength", pasteExpression.c_str(), mode, programmerNumberBase, bitLengthType); TraceLogger::GetInstance().LogInvalidPastedInputOccurred(L"ExponentLengthGreaterThanMaxLength", mode, programmerNumberBase, bitLengthType);
operands.clear(); operands.clear();
return operands; return operands;
} }
@ -402,9 +403,9 @@ pair<size_t, uint64_t> CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mo
wstring CopyPasteManager::SanitizeOperand(const wstring& operand) wstring CopyPasteManager::SanitizeOperand(const wstring& operand)
{ {
wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-' }; wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-', L'+' };
return Utils::RemoveUnwantedCharsFromWstring(operand, unWantedChars, ARRAYSIZE(unWantedChars)); return Utils::RemoveUnwantedCharsFromWstring(operand, unWantedChars, static_cast<int>(size(unWantedChars)));
} }
bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, unsigned long long int& result) bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, unsigned long long int& result)
@ -567,3 +568,21 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num
return len; return len;
} }
// return wstring after removing characters like space, comma, double quotes, and monetary prefix currency symbols supported by the Windows keyboard:
// yen or yuan(¥) - 165
// unspecified currency sign(¤) - 164
// Ghanaian cedi(₵) - 8373
// dollar or peso($) - 36
// colón(₡) - 8353
// won(₩) - 8361
// shekel(₪) - 8362
// naira(₦) - 8358
// Indian rupee(₹) - 8377
// pound(£) - 163
// euro(€) - 8364
wstring CopyPasteManager::RemoveUnwantedCharsFromWstring(const wstring& input)
{
wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237 };
return Utils::RemoveUnwantedCharsFromWstring(input, unWantedChars, 18);
}

View file

@ -58,6 +58,7 @@ namespace CalculatorApp
static size_t OperandLength(std::wstring operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1); static size_t OperandLength(std::wstring operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1);
static size_t StandardScientificOperandLength(std::wstring operand); static size_t StandardScientificOperandLength(std::wstring operand);
static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase); 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 MaxStandardOperandLength = 16;
static constexpr size_t MaxScientificOperandLength = 32; static constexpr size_t MaxScientificOperandLength = 32;

View file

@ -12,10 +12,11 @@ using namespace CalculatorApp::Common::DateCalculation;
DateCalculationEngine::DateCalculationEngine(_In_ String^ calendarIdentifier) DateCalculationEngine::DateCalculationEngine(_In_ String^ calendarIdentifier)
{ {
m_calendar = ref new Calendar(); m_calendar = ref new Calendar();
m_calendar->ChangeTimeZone("UTC");
m_calendar->ChangeCalendarSystem(calendarIdentifier); m_calendar->ChangeCalendarSystem(calendarIdentifier);
} }
// Adding Duration to a Date // Adding Duration to a Date
// Returns: True if function succeeds to calculate the date else returns False // 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) bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime *endDate)
{ {
@ -52,7 +53,7 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date
bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime *endDate) bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime *endDate)
{ {
// For Subtract the Algorithm is different than Add. Here the smaller units are subtracted first // For Subtract the Algorithm is different than Add. Here the smaller units are subtracted first
// and then the larger units. // and then the larger units.
try try
{ {
m_calendar->SetDateTime(startDate); m_calendar->SetDateTime(startDate);

View file

@ -21,10 +21,10 @@ namespace CalculatorApp
private: private:
// Explicit, and private, implementation of ICommand, this way of programming makes it so // 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 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 // 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. // code in the app calling Execute.
virtual void ExecuteImpl(Platform::Object^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::Execute virtual void ExecuteImpl(Platform::Object^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::Execute
{ {
TTarget^ target = m_weakTarget.Resolve<TTarget>(); TTarget^ target = m_weakTarget.Resolve<TTarget>();

View file

@ -56,7 +56,7 @@ namespace CalculatorApp
{ {
// Lights up all of the buttons in the given range // Lights up all of the buttons in the given range
// The range is defined by a pair of iterators // The range is defined by a pair of iterators
template <typename T> template <typename T>
void LightUpButtons(const T& buttons) void LightUpButtons(const T& buttons)
{ {
auto iterator = buttons.first; auto iterator = buttons.first;
@ -72,14 +72,14 @@ namespace CalculatorApp
void LightUpButton(ButtonBase^ button) void LightUpButton(ButtonBase^ button)
{ {
// If the button is a toggle button then we don't need // If the button is a toggle button then we don't need
// to change the UI of the button // to change the UI of the button
if (dynamic_cast<ToggleButton^>(button)) if (dynamic_cast<ToggleButton^>(button))
{ {
return; return;
} }
// The button will go into the visual Pressed state with this call // The button will go into the visual Pressed state with this call
VisualStateManager::GoToState(button, "Pressed", true); VisualStateManager::GoToState(button, "Pressed", true);
// This timer will fire after lightUpTime and make the button // This timer will fire after lightUpTime and make the button
@ -89,7 +89,7 @@ namespace CalculatorApp
TimeSpan lightUpTime{}; TimeSpan lightUpTime{};
lightUpTime.Duration = 500000L; // Half second (in 100-ns units) lightUpTime.Duration = 500000L; // Half second (in 100-ns units)
timer->Interval = lightUpTime; timer->Interval = lightUpTime;
WeakReference timerWeakReference(timer); WeakReference timerWeakReference(timer);
WeakReference buttonWeakReference(button); WeakReference buttonWeakReference(button);
timer->Tick += ref new EventHandler<Object^>( timer->Tick += ref new EventHandler<Object^>(
@ -206,7 +206,7 @@ void KeyboardShortcutManager::HonorEscape()
} }
void KeyboardShortcutManager::OnCharacterPropertyChanged( void KeyboardShortcutManager::OnCharacterPropertyChanged(
DependencyObject^ target, DependencyObject^ target,
String^ oldValue, String^ oldValue,
String^ newValue) String^ newValue)
{ {
@ -263,10 +263,10 @@ void KeyboardShortcutManager::OnVirtualKeyPropertyChanged(
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock); reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
auto button = static_cast<ButtonBase^>(target); auto button = static_cast<ButtonBase^>(target);
int viewId = Utils::GetWindowId(); int viewId = Utils::GetWindowId();
auto iterViewMap = s_VirtualKeysForButtons.find(viewId); auto iterViewMap = s_VirtualKeysForButtons.find(viewId);
// Check if the View Id has already been registered // Check if the View Id has already been registered
if (iterViewMap != s_VirtualKeysForButtons.end()) if (iterViewMap != s_VirtualKeysForButtons.end())
{ {
@ -281,7 +281,7 @@ void KeyboardShortcutManager::OnVirtualKeyPropertyChanged(
} }
void KeyboardShortcutManager::OnVirtualKeyControlChordPropertyChanged( void KeyboardShortcutManager::OnVirtualKeyControlChordPropertyChanged(
DependencyObject^ target, DependencyObject^ target,
MyVirtualKey /*oldValue*/, MyVirtualKey /*oldValue*/,
MyVirtualKey newValue) MyVirtualKey newValue)
{ {
@ -537,7 +537,7 @@ void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow^ sender, KeyEventArgs^
// Handle Ctrl + E for DateCalculator // Handle Ctrl + E for DateCalculator
if ((key == VirtualKey::E) && if ((key == VirtualKey::E) &&
isControlKeyPressed && isControlKeyPressed &&
!isShiftKeyPressed) !isShiftKeyPressed)
{ {
const auto& lookupMap = GetCurrentKeyDictionary(static_cast<MyVirtualKey>(key)); const auto& lookupMap = GetCurrentKeyDictionary(static_cast<MyVirtualKey>(key));
@ -710,7 +710,7 @@ void KeyboardShortcutManager::OnAcceleratorKeyActivated(CoreDispatcher^, Acceler
{ {
int viewId = Utils::GetWindowId(); int viewId = Utils::GetWindowId();
auto iterViewMap = s_AboutFlyout.find(viewId); auto iterViewMap = s_AboutFlyout.find(viewId);
if ((iterViewMap != s_AboutFlyout.end()) && (iterViewMap->second != nullptr)) if ((iterViewMap != s_AboutFlyout.end()) && (iterViewMap->second != nullptr))
{ {
iterViewMap->second->Hide(); iterViewMap->second->Hide();
@ -721,9 +721,9 @@ void KeyboardShortcutManager::OnAcceleratorKeyActivated(CoreDispatcher^, Acceler
void KeyboardShortcutManager::Initialize() void KeyboardShortcutManager::Initialize()
{ {
auto coreWindow = Window::Current->CoreWindow; auto coreWindow = Window::Current->CoreWindow;
coreWindow->CharacterReceived += coreWindow->CharacterReceived +=
ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(&KeyboardShortcutManager::OnCharacterReceivedHandler); ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(&KeyboardShortcutManager::OnCharacterReceivedHandler);
coreWindow->KeyDown += coreWindow->KeyDown +=
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(&KeyboardShortcutManager::OnKeyDownHandler); ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(&KeyboardShortcutManager::OnKeyDownHandler);
coreWindow->KeyUp += coreWindow->KeyUp +=
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(&KeyboardShortcutManager::OnKeyUpHandler); ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(&KeyboardShortcutManager::OnKeyUpHandler);
@ -758,7 +758,7 @@ void KeyboardShortcutManager::UpdateDropDownState(bool isOpen)
void KeyboardShortcutManager::UpdateDropDownState(Flyout^ aboutPageFlyout) void KeyboardShortcutManager::UpdateDropDownState(Flyout^ aboutPageFlyout)
{ {
int viewId = Utils::GetWindowId(); int viewId = Utils::GetWindowId();
if (s_AboutFlyout.find(viewId) != s_AboutFlyout.end()) if (s_AboutFlyout.find(viewId) != s_AboutFlyout.end())
{ {
s_AboutFlyout.erase(viewId); s_AboutFlyout.erase(viewId);
@ -803,7 +803,7 @@ void KeyboardShortcutManager::RegisterNewAppViewId()
{ {
s_CharacterForButtons.insert(std::make_pair(appViewId, std::multimap<wchar_t, WeakReference>())); s_CharacterForButtons.insert(std::make_pair(appViewId, std::multimap<wchar_t, WeakReference>()));
} }
if (s_VirtualKeysForButtons.find(appViewId) == s_VirtualKeysForButtons.end()) if (s_VirtualKeysForButtons.find(appViewId) == s_VirtualKeysForButtons.end())
{ {
s_VirtualKeysForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>())); s_VirtualKeysForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
@ -823,17 +823,17 @@ void KeyboardShortcutManager::RegisterNewAppViewId()
{ {
s_VirtualKeyAltChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>())); s_VirtualKeyAltChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
} }
if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end()) if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end())
{ {
s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>())); s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
} }
if (s_VirtualKeyInverseChordsForButtons.find(appViewId) == s_VirtualKeyInverseChordsForButtons.end()) if (s_VirtualKeyInverseChordsForButtons.find(appViewId) == s_VirtualKeyInverseChordsForButtons.end())
{ {
s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>())); s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
} }
if (s_VirtualKeyControlInverseChordsForButtons.find(appViewId) == s_VirtualKeyControlInverseChordsForButtons.end()) if (s_VirtualKeyControlInverseChordsForButtons.find(appViewId) == s_VirtualKeyControlInverseChordsForButtons.end())
{ {
s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>())); s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));

View file

@ -206,7 +206,7 @@ FontWeight LocalizationService::GetFontWeightOverride()
double LocalizationService::GetFontScaleFactorOverride(LanguageFontType fontType) double LocalizationService::GetFontScaleFactorOverride(LanguageFontType fontType)
{ {
assert(m_overrideFontApiValues); assert(m_overrideFontApiValues);
switch (fontType) switch (fontType)
{ {
case LanguageFontType::UIText: case LanguageFontType::UIText:
@ -271,12 +271,12 @@ void LocalizationService::UpdateFontFamilyAndSize(DependencyObject^ target)
{ {
control->FontSize = sizeToUse; control->FontSize = sizeToUse;
} }
else else
{ {
control->ClearValue(Control::FontSizeProperty); control->ClearValue(Control::FontSizeProperty);
} }
} }
else else
{ {
auto textBlock = dynamic_cast<TextBlock^>(target); auto textBlock = dynamic_cast<TextBlock^>(target);
if (textBlock) if (textBlock)
@ -290,7 +290,7 @@ void LocalizationService::UpdateFontFamilyAndSize(DependencyObject^ target)
{ {
textBlock->FontSize = sizeToUse; textBlock->FontSize = sizeToUse;
} }
else else
{ {
textBlock->ClearValue(TextBlock::FontSizeProperty); textBlock->ClearValue(TextBlock::FontSizeProperty);
} }
@ -309,7 +309,7 @@ void LocalizationService::UpdateFontFamilyAndSize(DependencyObject^ target)
{ {
richTextBlock->FontSize = sizeToUse; richTextBlock->FontSize = sizeToUse;
} }
else else
{ {
richTextBlock->ClearValue(RichTextBlock::FontSizeProperty); richTextBlock->ClearValue(RichTextBlock::FontSizeProperty);
} }
@ -328,7 +328,7 @@ void LocalizationService::UpdateFontFamilyAndSize(DependencyObject^ target)
{ {
textElement->FontSize = sizeToUse; textElement->FontSize = sizeToUse;
} }
else else
{ {
textElement->ClearValue(TextElement::FontSizeProperty); textElement->ClearValue(TextElement::FontSizeProperty);
} }
@ -416,7 +416,7 @@ IIterable<String^>^ LocalizationService::GetLanguageIdentifiers()
int result = GetUserDefaultLocaleName(currentLocale, LOCALE_NAME_MAX_LENGTH); int result = GetUserDefaultLocaleName(currentLocale, LOCALE_NAME_MAX_LENGTH);
if (result != 0) if (result != 0)
{ {
// GetUserDefaultLocaleName may return an invalid bcp47 language tag with trailing non-BCP47 friendly characters, // 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 // 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). // (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. // Therefore, if there is an underscore in the locale name, trim all characters from the underscore onwards.

View file

@ -4,6 +4,8 @@
#pragma once #pragma once
#include "LocalizationService.h" #include "LocalizationService.h"
#include <iterator>
namespace CalculatorApp namespace CalculatorApp
{ {
namespace Common namespace Common
@ -41,7 +43,7 @@ namespace CalculatorApp
result = GetLocaleInfoEx(m_resolvedName.c_str(), result = GetLocaleInfoEx(m_resolvedName.c_str(),
LOCALE_SDECIMAL, LOCALE_SDECIMAL,
decimalString, decimalString,
ARRAYSIZE(decimalString)); static_cast<int>(std::size(decimalString)));
if (result == 0) if (result == 0)
{ {
throw std::runtime_error("Unexpected error while getting locale info"); throw std::runtime_error("Unexpected error while getting locale info");
@ -51,7 +53,7 @@ namespace CalculatorApp
result = GetLocaleInfoEx(m_resolvedName.c_str(), result = GetLocaleInfoEx(m_resolvedName.c_str(),
LOCALE_STHOUSAND, LOCALE_STHOUSAND,
groupingSymbolString, groupingSymbolString,
ARRAYSIZE(groupingSymbolString)); static_cast<int>(std::size(groupingSymbolString)));
if (result == 0) if (result == 0)
{ {
throw std::runtime_error("Unexpected error while getting locale info"); throw std::runtime_error("Unexpected error while getting locale info");
@ -61,7 +63,7 @@ namespace CalculatorApp
result = GetLocaleInfoEx(m_resolvedName.c_str(), result = GetLocaleInfoEx(m_resolvedName.c_str(),
LOCALE_SGROUPING, LOCALE_SGROUPING,
numberGroupingString, numberGroupingString,
ARRAYSIZE(numberGroupingString)); static_cast<int>(std::size(numberGroupingString)));
if (result == 0) if (result == 0)
{ {
throw std::runtime_error("Unexpected error while getting locale info"); throw std::runtime_error("Unexpected error while getting locale info");
@ -72,7 +74,7 @@ namespace CalculatorApp
result = ::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, result = ::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT,
LOCALE_SLIST, LOCALE_SLIST,
listSeparatorString, listSeparatorString,
ARRAYSIZE(listSeparatorString)); // Max length of the expected return value is 4 static_cast<int>(std::size(listSeparatorString))); // Max length of the expected return value is 4
if (result == 0) if (result == 0)
{ {
throw std::runtime_error("Unexpected error while getting locale info"); throw std::runtime_error("Unexpected error while getting locale info");
@ -122,7 +124,7 @@ namespace CalculatorApp
::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, ::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT,
LOCALE_IFIRSTDAYOFWEEK, // The first day in a week LOCALE_IFIRSTDAYOFWEEK, // The first day in a week
reinterpret_cast<PWSTR>(day), // Argument is of type PWSTR reinterpret_cast<PWSTR>(day), // Argument is of type PWSTR
ARRAYSIZE(day)); // Max return size are 80 characters 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 // 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 // DayOfWeek enum value varies from 0, 1, .. 6 for Sunday, Monday, ... Saturday

View file

@ -20,11 +20,11 @@ namespace CalculatorApp
va_list args = NULL; va_list args = NULL;
va_start(args, pMessage); va_start(args, pMessage);
DWORD fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING, DWORD fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING,
pMessage, pMessage,
0, 0,
0, 0,
spBuffer.get(), spBuffer.get(),
length, length,
&args); &args);
va_end(args); va_end(args);

View file

@ -141,7 +141,7 @@ namespace CalculatorApp
property Platform::String^ AccessKey property Platform::String^ AccessKey
{ {
Platform::String^ get() Platform::String^ get()
{ {
return m_accessKey; return m_accessKey;
} }
@ -220,11 +220,11 @@ namespace CalculatorApp
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup^>^ CreateMenuOptions(); static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup^>^ CreateMenuOptions();
static Platform::String^ GetHeaderResourceKey(CategoryGroupType type); static Platform::String^ GetHeaderResourceKey(CategoryGroupType type);
internal: internal:
static NavCategoryGroup^ CreateCalculatorCategory(); static NavCategoryGroup^ CreateCalculatorCategory();
static NavCategoryGroup^ CreateConverterCategory(); static NavCategoryGroup^ CreateConverterCategory();
private: private:
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer); NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);

View file

@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#pragma once
#include "pch.h" #include "pch.h"
#include "TraceLogger.h" #include "TraceLogger.h"
#include "NetworkManager.h" #include "NetworkManager.h"
@ -59,7 +57,7 @@ namespace CalculatorApp
constexpr auto EVENT_NAME_MEMORY_FLYOUT_OPEN_BEGIN = L"MemoryFlyoutOpenBegin"; constexpr auto EVENT_NAME_MEMORY_FLYOUT_OPEN_BEGIN = L"MemoryFlyoutOpenBegin";
constexpr auto EVENT_NAME_MEMORY_FLYOUT_OPEN_END = L"MemoryFlyoutOpenEnd"; constexpr auto EVENT_NAME_MEMORY_FLYOUT_OPEN_END = L"MemoryFlyoutOpenEnd";
constexpr auto EVENT_NAME_MEMORY_CLEAR_ALL = L"MemoryClearAll"; constexpr auto EVENT_NAME_MEMORY_CLEAR_ALL = L"MemoryClearAll";
constexpr auto EVENT_NAME_INVALID_INPUT_PASTED = L"InvalidInputPasted"; constexpr auto EVENT_NAME_INVALID_PASTED_INPUT_OCCURRED = L"InvalidPastedInputOccurred";
constexpr auto EVENT_NAME_VALID_INPUT_PASTED = L"ValidInputPasted"; constexpr auto EVENT_NAME_VALID_INPUT_PASTED = L"ValidInputPasted";
constexpr auto EVENT_NAME_BITFLIP_PANE_CLICKED = L"BitFlipPaneClicked"; constexpr auto EVENT_NAME_BITFLIP_PANE_CLICKED = L"BitFlipPaneClicked";
constexpr auto EVENT_NAME_BITFLIP_BUTTONS_USED = L"BitFlipToggleButtonUsed"; constexpr auto EVENT_NAME_BITFLIP_BUTTONS_USED = L"BitFlipToggleButtonUsed";
@ -81,6 +79,9 @@ namespace CalculatorApp
constexpr auto EVENT_NAME_EXCEPTION = L"Exception"; constexpr auto EVENT_NAME_EXCEPTION = L"Exception";
constexpr auto PDT_PRIVACY_DATA_TAG = L"PartA_PrivTags";
constexpr auto PDT_PRODUCT_AND_SERVICE_USAGE = 0x0000'0000'0200'0000u;
#ifdef SEND_TELEMETRY #ifdef SEND_TELEMETRY
// c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords // c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords
// c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords // c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords
@ -102,7 +103,7 @@ namespace CalculatorApp
g_calculatorProvider( g_calculatorProvider(
L"MicrosoftCalculator", L"MicrosoftCalculator",
LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), // Microsoft Telemetry group LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), // Microsoft Telemetry group
GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 }), //Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0} GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 }), // Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0}
m_appLaunchActivity{ nullptr } m_appLaunchActivity{ nullptr }
{ {
// initialize the function array // initialize the function array
@ -247,7 +248,7 @@ namespace CalculatorApp
{ {
windowIdLog.insert(pair<int, bool>(windowId, false)); windowIdLog.insert(pair<int, bool>(windowId, false));
} }
// if the event is not logged already for the present mode // if the event is not logged already for the present mode
if (currentMode != mode) if (currentMode != mode)
{ {
currentMode = mode; currentMode = mode;
@ -270,7 +271,7 @@ namespace CalculatorApp
{ {
windowIdLog.insert(pair<int, bool>(windowId, false)); windowIdLog.insert(pair<int, bool>(windowId, false));
} }
// if the event is not logged already for the present mode // if the event is not logged already for the present mode
if (currentMode != mode) if (currentMode != mode)
{ {
currentMode = mode; currentMode = mode;
@ -292,7 +293,7 @@ namespace CalculatorApp
{ {
windowIdLog.insert(pair<int, bool>(windowId, false)); windowIdLog.insert(pair<int, bool>(windowId, false));
} }
// if the event is not logged already for the present mode // if the event is not logged already for the present mode
if (currentMode != mode) if (currentMode != mode)
{ {
currentMode = mode; currentMode = mode;
@ -481,9 +482,9 @@ namespace CalculatorApp
LogTelemetryEvent(EVENT_NAME_MEMORY_BODY_OPENED, fields); LogTelemetryEvent(EVENT_NAME_MEMORY_BODY_OPENED, fields);
} }
//If calculator is launched in any mode other than standard then this call will come which is not intended. But there is no way to avoid it. // If calculator is launched in any mode other than standard then this call will come which is not intended. But there is no way to avoid it.
//So don't use this function to analyze the count of mode change in session instead use CalculatorViewedInSession and ConverterViewedInSession to do that. // So don't use this function to analyze the count of mode change in session instead use CalculatorViewedInSession and ConverterViewedInSession to do that.
//Use of this function is to analyze perf of mode change. // Use of this function is to analyze perf of mode change.
void TraceLogger::LogModeChangeBegin(ViewMode fromMode, ViewMode toMode, int windowId) void TraceLogger::LogModeChangeBegin(ViewMode fromMode, ViewMode toMode, int windowId)
{ {
if (!GetTraceLoggingProviderEnabled()) return; if (!GetTraceLoggingProviderEnabled()) return;
@ -498,7 +499,7 @@ namespace CalculatorApp
} }
} }
//comment: same as LogModeChangeBegin // comment: same as LogModeChangeBegin
void TraceLogger::LogModeChangeEnd(ViewMode toMode, int windowId) const void TraceLogger::LogModeChangeEnd(ViewMode toMode, int windowId) const
{ {
if (!GetTraceLoggingProviderEnabled()) return; if (!GetTraceLoggingProviderEnabled()) return;
@ -577,7 +578,7 @@ namespace CalculatorApp
// Writer lock for the static resources // Writer lock for the static resources
reader_writer_lock::scoped_lock lock(s_traceLoggerLock); reader_writer_lock::scoped_lock lock(s_traceLoggerLock);
auto iterMap = s_memoryMap.find(windowId); auto iterMap = s_memoryMap.find(windowId);
LoggingFields fields{}; LoggingFields fields{};
LogTelemetryEvent(EVENT_NAME_MEMORY_CLEAR_ALL, fields); LogTelemetryEvent(EVENT_NAME_MEMORY_CLEAR_ALL, fields);
@ -641,17 +642,17 @@ namespace CalculatorApp
LogTelemetryEvent(EVENT_NAME_SINGLE_MEMORY_USED, fields); LogTelemetryEvent(EVENT_NAME_SINGLE_MEMORY_USED, fields);
} }
void TraceLogger::LogInvalidInputPasted(wstring_view reason, wstring_view pastedExpression, ViewMode mode, int programmerNumberBase, int bitLengthType) void TraceLogger::LogInvalidPastedInputOccurred(wstring_view reason, ViewMode mode, int programmerNumberBase, int bitLengthType)
{ {
if (!GetTraceLoggingProviderEnabled()) return; if (!GetTraceLoggingProviderEnabled()) return;
LoggingFields fields{}; LoggingFields fields{};
fields.AddString(L"Mode", NavCategory::GetFriendlyName(mode)->Data()); fields.AddString(L"Mode", NavCategory::GetFriendlyName(mode)->Data());
fields.AddString(L"Reason", reason); fields.AddString(L"Reason", reason);
fields.AddString(L"PastedExpression", pastedExpression);
fields.AddString(L"ProgrammerNumberBase", GetProgrammerType(programmerNumberBase).c_str()); fields.AddString(L"ProgrammerNumberBase", GetProgrammerType(programmerNumberBase).c_str());
fields.AddString(L"BitLengthType", GetProgrammerType(bitLengthType).c_str()); fields.AddString(L"BitLengthType", GetProgrammerType(bitLengthType).c_str());
LogTelemetryEvent(EVENT_NAME_INVALID_INPUT_PASTED, fields); fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
LogTelemetryEvent(EVENT_NAME_INVALID_PASTED_INPUT_OCCURRED, fields);
} }
void TraceLogger::LogValidInputPasted(ViewMode mode) const void TraceLogger::LogValidInputPasted(ViewMode mode) const

View file

@ -9,8 +9,8 @@
static const int maxFunctionSize = (int)CalculationManager::Command::CommandBINEDITEND; static const int maxFunctionSize = (int)CalculationManager::Command::CommandBINEDITEND;
// A trace logging provider can only be instantiated and registered once per module. // 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. // This class implements a singleton model ensure that only one instance is created.
namespace CalculatorApp namespace CalculatorApp
{ {
struct FuncLog struct FuncLog
@ -64,7 +64,7 @@ namespace CalculatorApp
void LogMemoryFlyoutOpenBegin(unsigned int) const; void LogMemoryFlyoutOpenBegin(unsigned int) const;
void LogDebug(std::wstring_view debugData); void LogDebug(std::wstring_view debugData);
void LogMemoryFlyoutOpenEnd(unsigned int) const; void LogMemoryFlyoutOpenEnd(unsigned int) const;
void LogInvalidInputPasted(std::wstring_view reason, std::wstring_view pastedExpression, CalculatorApp::Common::ViewMode mode, int ProgrammerNumberBase, int bitLengthType); void LogInvalidPastedInputOccurred(std::wstring_view reason, CalculatorApp::Common::ViewMode mode, int ProgrammerNumberBase, int bitLengthType);
void LogValidInputPasted(CalculatorApp::Common::ViewMode mode) const; void LogValidInputPasted(CalculatorApp::Common::ViewMode mode) const;
void UpdateFunctionUsage(int func); void UpdateFunctionUsage(int func);
void LogFunctionUsage(int); void LogFunctionUsage(int);
@ -105,7 +105,7 @@ namespace CalculatorApp
// Any new Log method should // 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 // 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 // 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 // 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 // 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 LogTelemetryEvent(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const;

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
// //
@ -54,7 +54,7 @@ double Utils::GetDoubleFromWstring(wstring input)
return ::atof(inputString.c_str()); return ::atof(inputString.c_str());
} }
//returns windowId for the current view // Returns windowId for the current view
int Utils::GetWindowId() int Utils::GetWindowId()
{ {
int windowId = -1; int windowId = -1;
@ -80,20 +80,13 @@ void Utils::RunOnUIThreadNonblocking(std::function<void()>&& function, _In_ Core
} }
} }
// returns if the last character of a wstring is the target wchar_t // Returns if the last character of a wstring is the target wchar_t
bool Utils::IsLastCharacterTarget(_In_ wstring const &input, _In_ wchar_t target) bool Utils::IsLastCharacterTarget(_In_ wstring const &input, _In_ wchar_t target)
{ {
return !input.empty() && input.back() == target; return !input.empty() && input.back() == target;
} }
//return wstring after removing characters like space, comma, and double quotes // Return wstring after removing characters specified by unwantedChars array
wstring Utils::RemoveUnwantedCharsFromWstring(wstring input)
{
wchar_t unWantedChars[] = { L' ', L',', L'"', 8234, 8235, 8236, 8237 };
return RemoveUnwantedCharsFromWstring(input, unWantedChars, 6);
}
//return wstring after removing characters specified by unwantedChars array
wstring Utils::RemoveUnwantedCharsFromWstring(wstring input, wchar_t* unwantedChars, unsigned int size) wstring Utils::RemoveUnwantedCharsFromWstring(wstring input, wchar_t* unwantedChars, unsigned int size)
{ {
for (unsigned int i = 0; i < size; ++i) for (unsigned int i = 0; i < size; ++i)
@ -110,7 +103,7 @@ void Utils::SerializeCommandsAndTokens(_In_ shared_ptr<CalculatorVector <pair<ws
unsigned int commandsSize; unsigned int commandsSize;
IFTPlatformException(commands->GetSize(&commandsSize)); IFTPlatformException(commands->GetSize(&commandsSize));
// save the size of the commands vector // Save the size of the commands vector
writer->WriteUInt32(commandsSize); writer->WriteUInt32(commandsSize);
SerializeCommandVisitor cmdVisitor(writer); SerializeCommandVisitor cmdVisitor(writer);

View file

@ -42,10 +42,16 @@
}\ }\
} private: t m_##n; public: } private: t m_##n; public:
#define NAMED_OBSERVABLE_PROPERTY_RW(t, n)\ #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)\ OBSERVABLE_PROPERTY_RW(t, n)\
private: property Platform::StringReference n##_PropertyName {\ internal: static property Platform::String^ n##PropertyName {\
Platform::StringReference get() { return Platform::StringReference(L#n); }\ Platform::String^ get() { return Platform::StringReference(L#n); }\
} public: } public:
#define OBSERVABLE_PROPERTY_FIELD(n) m_##n #define OBSERVABLE_PROPERTY_FIELD(n) m_##n
@ -54,11 +60,11 @@
#ifndef UNIT_TESTS #ifndef UNIT_TESTS
#define OBSERVABLE_OBJECT() virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;\ #define OBSERVABLE_OBJECT() virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;\
internal: void RaisePropertyChanged(Platform::String^ p) {\ internal: void RaisePropertyChanged(Platform::String^ p) {\
PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); } public: PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); } public:
#else #else
#define OBSERVABLE_OBJECT() virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;\ #define OBSERVABLE_OBJECT() virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;\
internal: void RaisePropertyChanged(Platform::String^ p) {\ internal: void RaisePropertyChanged(Platform::String^ p) {\
} public: } public:
#endif #endif
// The callback specified in the macro is a method in the class that will be called every time the object changes // The callback specified in the macro is a method in the class that will be called every time the object changes
@ -68,21 +74,21 @@
internal: void RaisePropertyChanged(Platform::String^ p) {\ internal: void RaisePropertyChanged(Platform::String^ p) {\
PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p));\ PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p));\
c(p);\ c(p);\
} public: } public:
#else #else
#define OBSERVABLE_OBJECT_CALLBACK(c) virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;\ #define OBSERVABLE_OBJECT_CALLBACK(c) virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;\
internal: void RaisePropertyChanged(Platform::String^ p) {\ internal: void RaisePropertyChanged(Platform::String^ p) {\
c(p);\ c(p);\
} public: } public:
#endif #endif
// The variable member generated by this macro should not be used in the class code, use the // The variable member generated by this macro should not be used in the class code, use the
// property getter instead. // property getter instead.
#define COMMAND_FOR_METHOD(p, m) property Windows::UI::Xaml::Input::ICommand^ p {\ #define COMMAND_FOR_METHOD(p, m) property Windows::UI::Xaml::Input::ICommand^ p {\
Windows::UI::Xaml::Input::ICommand^ get() {\ Windows::UI::Xaml::Input::ICommand^ get() {\
if (!donotuse_##p) {\ if (!donotuse_##p) {\
donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\ donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\
} return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; public: } return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; public:
#define DEPENDENCY_PROPERTY_DECLARATION(t, n)\ #define DEPENDENCY_PROPERTY_DECLARATION(t, n)\
property t n {\ property t n {\
@ -141,7 +147,7 @@ namespace Utils
const wchar_t PDF = 0x202c; // Pop Directional Formatting const wchar_t PDF = 0x202c; // Pop Directional Formatting
const wchar_t LRO = 0x202d; // Left-to-Right Override const wchar_t LRO = 0x202d; // Left-to-Right Override
// Regular DependencyProperty // Regular DependencyProperty
template <typename TOwner, typename TType> template <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty( Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(
_In_ const wchar_t* const name, _In_ const wchar_t* const name,
@ -205,7 +211,7 @@ namespace Utils
ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
} }
// Attached DependencyProperty // Attached DependencyProperty
template <typename TOwner, typename TType> template <typename TOwner, typename TType>
Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached( Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(
_In_ const wchar_t* const name, _In_ const wchar_t* const name,
@ -280,7 +286,6 @@ namespace Utils
Platform::String^ GetStringValue(Platform::String^ input); Platform::String^ GetStringValue(Platform::String^ input);
bool IsLastCharacterTarget(std::wstring const &input, wchar_t target); bool IsLastCharacterTarget(std::wstring const &input, wchar_t target);
std::wstring RemoveUnwantedCharsFromWstring(std::wstring inputString, wchar_t* unwantedChars, unsigned int size); std::wstring RemoveUnwantedCharsFromWstring(std::wstring inputString, wchar_t* unwantedChars, unsigned int size);
std::wstring RemoveUnwantedCharsFromWstring(std::wstring input);
double GetDoubleFromWstring(std::wstring input); double GetDoubleFromWstring(std::wstring input);
int GetWindowId(); int GetWindowId();
void RunOnUIThreadNonblocking(std::function<void()>&& function, _In_ Windows::UI::Core::CoreDispatcher^ currentDispatcher); void RunOnUIThreadNonblocking(std::function<void()>&& function, _In_ Windows::UI::Core::CoreDispatcher^ currentDispatcher);

View file

@ -14,9 +14,9 @@ namespace CalculatorApp { namespace Common
private: private:
virtual Platform::Object^ Convert( virtual Platform::Object^ Convert(
Platform::Object^ value, Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/, Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/, Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{ {
// Pass through as we don't want to change the value from the source // Pass through as we don't want to change the value from the source
@ -24,9 +24,9 @@ namespace CalculatorApp { namespace Common
} }
virtual Platform::Object^ ConvertBack( virtual Platform::Object^ ConvertBack(
Platform::Object^ value, Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/, Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/, Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{ {
if (value) if (value)
@ -47,9 +47,9 @@ namespace CalculatorApp { namespace Common
private: private:
virtual Platform::Object^ Convert( virtual Platform::Object^ Convert(
Platform::Object^ value, Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/, Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/, Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{ {
// Pass through as we don't want to change the value from the source // Pass through as we don't want to change the value from the source
@ -57,9 +57,9 @@ namespace CalculatorApp { namespace Common
} }
virtual Platform::Object^ ConvertBack( virtual Platform::Object^ ConvertBack(
Platform::Object^ value, Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/, Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object^ /*parameter*/, Platform::Object^ /*parameter*/,
Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack Platform::String^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{ {
// The value to be valid has to be a boxed int32 value // The value to be valid has to be a boxed int32 value

View file

@ -203,7 +203,7 @@ void CurrencyDataLoader::LoadData()
} }
} }
co_return didLoad; co_return didLoad;
}).then([this](bool didLoad) }).then([this](bool didLoad)
{ {
UpdateDisplayedTimestamp(); UpdateDisplayedTimestamp();
@ -329,7 +329,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromCacheAsync()
{ {
loadComplete = co_await TryLoadDataFromWebAsync(); loadComplete = co_await TryLoadDataFromWebAsync();
} }
if (!loadComplete) if (!loadComplete)
{ {
loadComplete = co_await TryFinishLoadFromCacheAsync(); loadComplete = co_await TryFinishLoadFromCacheAsync();

View file

@ -87,7 +87,7 @@ namespace CalculatorApp
bool TryParseWebResponses( bool TryParseWebResponses(
_In_ Platform::String^ staticDataJson, _In_ Platform::String^ staticDataJson,
_In_ Platform::String^ allRatiosJson, _In_ Platform::String^ allRatiosJson,
_Inout_ std::vector<UCM::CurrencyStaticData>& staticData, _Inout_ std::vector<UCM::CurrencyStaticData>& staticData,
_Inout_ CurrencyRatioMap& allRatiosData); _Inout_ CurrencyRatioMap& allRatiosData);
bool TryParseStaticData(_In_ Platform::String^ rawJson, _Inout_ std::vector<UCM::CurrencyStaticData>& staticData); bool TryParseStaticData(_In_ Platform::String^ rawJson, _Inout_ std::vector<UCM::CurrencyStaticData>& staticData);

View file

@ -200,7 +200,7 @@ void UnitConverterDataLoader::GetUnits(_In_ unordered_map<ViewMode, vector<Order
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Exbibits, GetLocalizedStringName(L"UnitName_Exbibits"), GetLocalizedStringName(L"UnitAbbreviation_Exbibits"), 24 }); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Exbibits, GetLocalizedStringName(L"UnitName_Exbibits"), GetLocalizedStringName(L"UnitAbbreviation_Exbibits"), 24 });
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Exbibytes, GetLocalizedStringName(L"UnitName_Exbibytes"), GetLocalizedStringName(L"UnitAbbreviation_Exbibytes"), 26 }); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Exbibytes, GetLocalizedStringName(L"UnitName_Exbibytes"), GetLocalizedStringName(L"UnitAbbreviation_Exbibytes"), 26 });
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gibibits, GetLocalizedStringName(L"UnitName_Gibibits"), GetLocalizedStringName(L"UnitAbbreviation_Gibibits"), 12 }); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gibibits, GetLocalizedStringName(L"UnitName_Gibibits"), GetLocalizedStringName(L"UnitAbbreviation_Gibibits"), 12 });
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gibibytes, GetLocalizedStringName(L"UnitName_Gibibytes"), GetLocalizedStringName(L"UnitAbbreviation_Gibibytes"), 14 }); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gibibytes, GetLocalizedStringName(L"UnitName_Gibibytes"), GetLocalizedStringName(L"UnitAbbreviation_Gibibytes"), 14 });
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gigabit, GetLocalizedStringName(L"UnitName_Gigabit"), GetLocalizedStringName(L"UnitAbbreviation_Gigabit"), 11 }); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gigabit, GetLocalizedStringName(L"UnitName_Gigabit"), GetLocalizedStringName(L"UnitAbbreviation_Gigabit"), 11 });
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gigabyte, GetLocalizedStringName(L"UnitName_Gigabyte"), GetLocalizedStringName(L"UnitAbbreviation_Gigabyte"),13, true, false, false}); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Gigabyte, GetLocalizedStringName(L"UnitName_Gigabyte"), GetLocalizedStringName(L"UnitAbbreviation_Gigabyte"),13, true, false, false});
dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Kibibits, GetLocalizedStringName(L"UnitName_Kibibits"), GetLocalizedStringName(L"UnitAbbreviation_Kibibits"), 4 }); dataUnits.push_back(OrderedUnit{ UnitConverterUnits::Data_Kibibits, GetLocalizedStringName(L"UnitName_Kibibits"), GetLocalizedStringName(L"UnitAbbreviation_Kibibits"), 4 });

View file

@ -22,14 +22,14 @@ using namespace Windows::Globalization;
using namespace Windows::Globalization::DateTimeFormatting; using namespace Windows::Globalization::DateTimeFormatting;
using namespace Windows::System::UserProfile; using namespace Windows::System::UserProfile;
namespace CalculatorApp::ViewModel::DateCalculatorViewModelProperties namespace
{ {
StringReference StrDateDiffResult(L"StrDateDiffResult"); StringReference StrDateDiffResultPropertyName(L"StrDateDiffResult");
StringReference StrDateDiffResultAutomationName(L"StrDateDiffResultAutomationName"); StringReference StrDateDiffResultAutomationNamePropertyName(L"StrDateDiffResultAutomationName");
StringReference StrDateDiffResultInDays(L"StrDateDiffResultInDays"); StringReference StrDateDiffResultInDaysPropertyName(L"StrDateDiffResultInDays");
StringReference StrDateResult(L"StrDateResult"); StringReference StrDateResultPropertyName(L"StrDateResult");
StringReference StrDateResultAutomationName(L"StrDateResultAutomationName"); StringReference StrDateResultAutomationNamePropertyName(L"StrDateResultAutomationName");
StringReference IsDiffInDays(L"IsDiffInDays"); StringReference IsDiffInDaysPropertyName(L"IsDiffInDays");
} }
DateCalculatorViewModel::DateCalculatorViewModel() : DateCalculatorViewModel::DateCalculatorViewModel() :
@ -43,11 +43,7 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
m_StrDateDiffResultAutomationName(L""), m_StrDateDiffResultAutomationName(L""),
m_StrDateDiffResultInDays(L""), m_StrDateDiffResultInDays(L""),
m_StrDateResult(L""), m_StrDateResult(L""),
m_StrDateResultAutomationName(L""), m_StrDateResultAutomationName(L"")
m_fromDate({ 0 }),
m_toDate({ 0 }),
m_startDate({ 0 }),
m_dateResult({ 0 })
{ {
const auto& localizationSettings = LocalizationSettings::GetInstance(); const auto& localizationSettings = LocalizationSettings::GetInstance();
@ -56,24 +52,24 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
// Initialize Date Calc engine // Initialize Date Calc engine
m_dateCalcEngine = make_shared<DateCalculationEngine>(localizationSettings.GetCalendarIdentifier()); m_dateCalcEngine = make_shared<DateCalculationEngine>(localizationSettings.GetCalendarIdentifier());
// Initialize dates of DatePicker controls to today's date // Initialize dates of DatePicker controls to today's date
auto calendar = ref new Calendar(); auto calendar = ref new Calendar();
// We force the timezone to UTC, in order to avoid being affected by Daylight Saving Time
// when we calculate the difference between 2 dates.
calendar->ChangeTimeZone("UTC");
auto today = calendar->GetDateTime(); auto today = calendar->GetDateTime();
// FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC) // FromDate and ToDate should be clipped (adjusted to a consistent hour in UTC)
m_fromDate = today; m_fromDate = ClipTime(today);
m_toDate = today; m_toDate = ClipTime(today);
FromDate = ClipTime(today);
ToDate = ClipTime(today);
// StartDate should not be clipped // StartDate should not be clipped
StartDate = today; m_startDate = today;
m_dateResult = today; m_dateResult = today;
// Initialize the list separator delimiter appended with a space at the end, e.g. ", " // Initialize the list separator delimiter appended with a space at the end, e.g. ", "
// This will be used for date difference formatting: Y years, M months, W weeks, D days // This will be used for date difference formatting: Y years, M months, W weeks, D days
m_listSeparator = ref new String((localizationSettings.GetListSeparator() + L" ").c_str()); m_listSeparator = localizationSettings.GetListSeparator() + L" ";
// Initialize the output results // Initialize the output results
UpdateDisplayResult(); UpdateDisplayResult();
@ -86,15 +82,6 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
m_offsetValues->Append(ref new String(numberStr.c_str())); m_offsetValues->Append(ref new String(numberStr.c_str()));
} }
/* In the ClipTime function, we used to change timezone to UTC before clipping the time.
The comment from the previous developers said this was done to eliminate the effects of
Daylight Savings Time. We can't think of a good reason why this change in timezone is
necessary and did find bugs related to the change, therefore, we have removed the
change. Just in case, we will see if the clipped time is ever a different day from the
original day, which would hopefully indicate the change in timezone was actually
necessary. We will collect telemetry if we find this case. If we don't see any
telemetry events after the application has been used for some time, we will feel safe
and can remove this function. */
DayOfWeek trueDayOfWeek = calendar->DayOfWeek; DayOfWeek trueDayOfWeek = calendar->DayOfWeek;
DateTime clippedTime = ClipTime(today); DateTime clippedTime = ClipTime(today);
@ -110,18 +97,18 @@ DateCalculatorViewModel::DateCalculatorViewModel() :
void DateCalculatorViewModel::OnPropertyChanged(_In_ String^ prop) void DateCalculatorViewModel::OnPropertyChanged(_In_ String^ prop)
{ {
if (prop == DateCalculatorViewModelProperties::StrDateDiffResult) if (prop == StrDateDiffResultPropertyName)
{ {
UpdateStrDateDiffResultAutomationName(); UpdateStrDateDiffResultAutomationName();
} }
else if (prop == DateCalculatorViewModelProperties::StrDateResult) else if (prop == StrDateResultPropertyName)
{ {
UpdateStrDateResultAutomationName(); UpdateStrDateResultAutomationName();
} }
else if (prop != DateCalculatorViewModelProperties::StrDateDiffResultAutomationName else if (prop != StrDateDiffResultAutomationNamePropertyName
&& prop != DateCalculatorViewModelProperties::StrDateDiffResultInDays && prop != StrDateDiffResultInDaysPropertyName
&& prop != DateCalculatorViewModelProperties::StrDateResultAutomationName && prop != StrDateResultAutomationNamePropertyName
&& prop != DateCalculatorViewModelProperties::IsDiffInDays) && prop != IsDiffInDaysPropertyName)
{ {
OnInputsChanged(); OnInputsChanged();
} }
@ -180,9 +167,9 @@ void DateCalculatorViewModel::UpdateDisplayResult()
StrDateDiffResultInDays = L""; StrDateDiffResultInDays = L"";
StrDateDiffResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_SameDates"); StrDateDiffResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_SameDates");
} }
else if ((m_dateDiffResult.year == 0) && else if ((m_dateDiffResult.year == 0) &&
(m_dateDiffResult.month == 0) && (m_dateDiffResult.month == 0) &&
(m_dateDiffResult.week == 0)) (m_dateDiffResult.week == 0))
{ {
IsDiffInDays = true; IsDiffInDays = true;
StrDateDiffResultInDays = L""; StrDateDiffResultInDays = L"";
@ -245,22 +232,23 @@ void DateCalculatorViewModel::InitializeDateOutputFormats(_In_ String^ calendarI
String^ DateCalculatorViewModel::GetDateDiffString() const String^ DateCalculatorViewModel::GetDateDiffString() const
{ {
String^ result = L""; wstring result;
bool addDelimiter = false; bool addDelimiter = false;
AppResourceProvider resourceLoader = AppResourceProvider::GetInstance(); AppResourceProvider resourceLoader = AppResourceProvider::GetInstance();
auto yearCount = m_dateDiffResult.year; auto yearCount = m_dateDiffResult.year;
if (yearCount > 0) if (yearCount > 0)
{ {
result = String::Concat(GetLocalizedNumberString(yearCount), L" "); result += GetLocalizedNumberString(yearCount)->Data();
result += L" ";
if (yearCount > 1) if (yearCount > 1)
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Years")); result += resourceLoader.GetResourceString(L"Date_Years")->Data();
} }
else else
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Year")); result += resourceLoader.GetResourceString(L"Date_Year")->Data();
} }
// set the flags to add a delimiter whenever the next unit is added // set the flags to add a delimiter whenever the next unit is added
@ -272,22 +260,23 @@ String^ DateCalculatorViewModel::GetDateDiffString() const
{ {
if (addDelimiter) if (addDelimiter)
{ {
result = String::Concat(result, m_listSeparator); result += m_listSeparator;
} }
else else
{ {
addDelimiter = true; addDelimiter = true;
} }
result = String::Concat(result, String::Concat(GetLocalizedNumberString(monthCount), L" ")); result += GetLocalizedNumberString(monthCount)->Data();
result += L" ";
if (monthCount > 1) if (monthCount > 1)
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Months")); result += resourceLoader.GetResourceString(L"Date_Months")->Data();
} }
else else
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Month")); result += resourceLoader.GetResourceString(L"Date_Month")->Data();
} }
} }
@ -296,22 +285,23 @@ String^ DateCalculatorViewModel::GetDateDiffString() const
{ {
if (addDelimiter) if (addDelimiter)
{ {
result = String::Concat(result, m_listSeparator); result += m_listSeparator;
} }
else else
{ {
addDelimiter = true; addDelimiter = true;
} }
result = String::Concat(result, String::Concat(GetLocalizedNumberString(weekCount), L" ")); result += GetLocalizedNumberString(weekCount)->Data();
result += L" ";
if (weekCount > 1) if (weekCount > 1)
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Weeks")); result += resourceLoader.GetResourceString(L"Date_Weeks")->Data();
} }
else else
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Week")); result += resourceLoader.GetResourceString(L"Date_Week")->Data();
} }
} }
@ -320,43 +310,45 @@ String^ DateCalculatorViewModel::GetDateDiffString() const
{ {
if (addDelimiter) if (addDelimiter)
{ {
result = String::Concat(result, m_listSeparator); result += m_listSeparator;
} }
else else
{ {
addDelimiter = true; addDelimiter = true;
} }
result = String::Concat(result, String::Concat(GetLocalizedNumberString(dayCount), L" ")); result += GetLocalizedNumberString(dayCount)->Data();
result += L" ";
if (dayCount > 1) if (dayCount > 1)
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Days")); result += resourceLoader.GetResourceString(L"Date_Days")->Data();
} }
else else
{ {
result = String::Concat(result, resourceLoader.GetResourceString(L"Date_Day")); result += resourceLoader.GetResourceString(L"Date_Day")->Data();
} }
} }
return result; return ref new String(result.data());
} }
String^ DateCalculatorViewModel::GetDateDiffStringInDays() const String^ DateCalculatorViewModel::GetDateDiffStringInDays() const
{ {
String^ strDateUnit; wstring result = GetLocalizedNumberString(m_dateDiffResultInDays.day)->Data();
result += L" ";
// Display the result as '1 day' or 'N days' // Display the result as '1 day' or 'N days'
if (m_dateDiffResultInDays.day > 1) if (m_dateDiffResultInDays.day > 1)
{ {
strDateUnit = AppResourceProvider::GetInstance().GetResourceString(L"Date_Days"); result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Days")->Data();
} }
else else
{ {
strDateUnit = AppResourceProvider::GetInstance().GetResourceString(L"Date_Day"); result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Day")->Data();
} }
return String::Concat(GetLocalizedNumberString(m_dateDiffResultInDays.day), String::Concat(L" ", strDateUnit)); return ref new String(result.data());
} }
void DateCalculatorViewModel::OnCopyCommand(Platform::Object^ parameter) void DateCalculatorViewModel::OnCopyCommand(Platform::Object^ parameter)
@ -378,13 +370,14 @@ String^ DateCalculatorViewModel::GetLocalizedNumberString(int value) const
return ref new String(numberStr.c_str()); return ref new String(numberStr.c_str());
} }
// Adjusts the given DateTime to 12AM of the same day // Adjusts the given DateTime to 12AM (UTC) of the same day
DateTime DateCalculatorViewModel::ClipTime(DateTime dateTime) DateTime DateCalculatorViewModel::ClipTime(DateTime dateTime)
{ {
auto calendar = ref new Calendar(); auto calendar = ref new Calendar();
calendar->ChangeTimeZone("UTC");
calendar->SetDateTime(dateTime); calendar->SetDateTime(dateTime);
calendar->Period = 1; calendar->Period = calendar->FirstPeriodInThisDay;
calendar->Hour = 12; calendar->Hour = calendar->FirstHourInThisPeriod;
calendar->Minute = 0; calendar->Minute = 0;
calendar->Second = 0; calendar->Second = 0;
calendar->Nanosecond = 0; calendar->Nanosecond = 0;

View file

@ -23,8 +23,8 @@ namespace CalculatorApp
// Input Properties // Input Properties
OBSERVABLE_PROPERTY_RW(bool, IsDateDiffMode); OBSERVABLE_PROPERTY_RW(bool, IsDateDiffMode);
OBSERVABLE_PROPERTY_RW(bool, IsAddMode); OBSERVABLE_PROPERTY_RW(bool, IsAddMode);
OBSERVABLE_PROPERTY_RW(bool, IsDiffInDays); // If diff is only in days or the dates are the same, OBSERVABLE_PROPERTY_R(bool, IsDiffInDays); // If diff is only in days or the dates are the same,
// then show only one result and avoid redundancy // then show only one result and avoid redundancy
OBSERVABLE_PROPERTY_RW(int, DaysOffset); OBSERVABLE_PROPERTY_RW(int, DaysOffset);
OBSERVABLE_PROPERTY_RW(int, MonthsOffset); OBSERVABLE_PROPERTY_RW(int, MonthsOffset);
@ -82,11 +82,11 @@ namespace CalculatorApp
} }
// Output Properties // Output Properties
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResult); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResult);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResultAutomationName); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResultAutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateDiffResultInDays); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateDiffResultInDays);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateResult); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateResult);
OBSERVABLE_PROPERTY_RW(Platform::String^, StrDateResultAutomationName); OBSERVABLE_PROPERTY_R(Platform::String^, StrDateResultAutomationName);
COMMAND_FOR_METHOD(CopyCommand, DateCalculatorViewModel::OnCopyCommand); COMMAND_FOR_METHOD(CopyCommand, DateCalculatorViewModel::OnCopyCommand);
@ -104,8 +104,6 @@ namespace CalculatorApp
Platform::String^ GetLocalizedNumberString(int value) const; Platform::String^ GetLocalizedNumberString(int value) const;
static Windows::Foundation::DateTime ClipTime(Windows::Foundation::DateTime dateTime); static Windows::Foundation::DateTime ClipTime(Windows::Foundation::DateTime dateTime);
static void CheckClipTimeSameDay(Windows::Globalization::Calendar^ reference);
property bool IsOutOfBound property bool IsOutOfBound
{ {
bool get() { return m_isOutOfBound; } bool get() { return m_isOutOfBound; }
@ -146,7 +144,7 @@ namespace CalculatorApp
CalculatorApp::Common::DateCalculation::DateUnit m_daysOutputFormat; CalculatorApp::Common::DateCalculation::DateUnit m_daysOutputFormat;
CalculatorApp::Common::DateCalculation::DateUnit m_allDateUnitsOutputFormat; CalculatorApp::Common::DateCalculation::DateUnit m_allDateUnitsOutputFormat;
Windows::Globalization::DateTimeFormatting::DateTimeFormatter^ m_dateTimeFormatter; Windows::Globalization::DateTimeFormatting::DateTimeFormatter^ m_dateTimeFormatter;
Platform::String^ m_listSeparator; std::wstring m_listSeparator;
}; };
} }
} }

View file

@ -17,18 +17,18 @@ namespace CalculatorApp
internal: internal:
HistoryItemViewModel(Platform::String^ expression, HistoryItemViewModel(Platform::String^ expression,
Platform::String^ result, Platform::String^ result,
_In_ std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const &spTokens, _In_ std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const &spTokens,
_In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &spCommands); _In_ std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const &spCommands);
std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const& GetTokens() std::shared_ptr<CalculatorVector <std::pair<std::wstring, int>>> const& GetTokens()
{ {
return m_spTokens; return m_spTokens;
} }
std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const& GetCommands() std::shared_ptr<CalculatorVector<std::shared_ptr<IExpressionCommand>>> const& GetCommands()
{ {
return m_spCommands; return m_spCommands;
} }
public: public:

View file

@ -64,7 +64,7 @@ void HistoryViewModel::ReloadHistory(_In_ ViewMode currentMode)
if (historyListModel.size() > 0) if (historyListModel.size() > 0)
{ {
for (auto ritr = historyListModel.rbegin(); ritr != historyListModel.rend(); ++ritr) for (auto ritr = historyListModel.rbegin(); ritr != historyListModel.rend(); ++ritr)
{ {
wstring expression = (*ritr)->historyItemVector.expression; wstring expression = (*ritr)->historyItemVector.expression;
wstring result = (*ritr)->historyItemVector.result; wstring result = (*ritr)->historyItemVector.result;
localizer.LocalizeDisplayValue(&expression); localizer.LocalizeDisplayValue(&expression);

View file

@ -30,37 +30,34 @@ constexpr int StandardModePrecision = 16;
constexpr int ScientificModePrecision = 32; constexpr int ScientificModePrecision = 32;
constexpr int ProgrammerModePrecision = 64; constexpr int ProgrammerModePrecision = 64;
namespace CalculatorApp::ViewModel namespace
{ {
namespace CalculatorViewModelProperties StringReference IsStandardPropertyName(L"IsStandard");
{ StringReference IsScientificPropertyName(L"IsScientific");
StringReference IsMemoryEmpty(L"IsMemoryEmpty"); StringReference IsProgrammerPropertyName(L"IsProgrammer");
StringReference IsScientific(L"IsScientific"); StringReference DisplayValuePropertyName(L"DisplayValue");
StringReference IsStandard(L"IsStandard"); StringReference CalculationResultAutomationNamePropertyName(L"CalculationResultAutomationName");
StringReference IsProgrammer(L"IsProgrammer"); }
StringReference DisplayValue(L"DisplayValue");
StringReference IsInError(L"IsInError"); namespace CalculatorResourceKeys
StringReference BinaryDisplayValue(L"BinaryDisplayValue"); {
} StringReference CalculatorExpression(L"Format_CalculatorExpression");
StringReference CalculatorResults(L"Format_CalculatorResults");
namespace CalculatorResourceKeys StringReference CalculatorResults_DecimalSeparator_Announced(L"Format_CalculatorResults_Decimal");
{ StringReference HexButton(L"Format_HexButtonValue");
StringReference CalculatorExpression(L"Format_CalculatorExpression"); StringReference DecButton(L"Format_DecButtonValue");
StringReference CalculatorResults(L"Format_CalculatorResults"); StringReference OctButton(L"Format_OctButtonValue");
StringReference CalculatorResults_DecimalSeparator_Announced(L"Format_CalculatorResults_Decimal"); StringReference BinButton(L"Format_BinButtonValue");
StringReference HexButton(L"Format_HexButtonValue"); StringReference LeftParenthesisAutomationFormat(L"Format_OpenParenthesisAutomationNamePrefix");
StringReference DecButton(L"Format_DecButtonValue"); StringReference OpenParenthesisCountAutomationFormat(L"Format_OpenParenthesisCountAutomationNamePrefix");
StringReference OctButton(L"Format_OctButtonValue"); StringReference NoParenthesisAdded(L"NoRightParenthesisAdded_Announcement");
StringReference BinButton(L"Format_BinButtonValue"); StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached");
StringReference LeftParenthesisAutomationFormat(L"Format_OpenParenthesisAutomationNamePrefix"); StringReference ButtonPressFeedbackFormat(L"Format_ButtonPressAuditoryFeedback");
StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached"); StringReference MemorySave(L"Format_MemorySave");
StringReference ButtonPressFeedbackFormat(L"Format_ButtonPressAuditoryFeedback"); StringReference MemoryItemChanged(L"Format_MemorySlotChanged");
StringReference MemorySave(L"Format_MemorySave"); StringReference MemoryItemCleared(L"Format_MemorySlotCleared");
StringReference MemoryItemChanged(L"Format_MemorySlotChanged"); StringReference MemoryCleared(L"Memory_Cleared");
StringReference MemoryItemCleared(L"Format_MemorySlotCleared"); StringReference DisplayCopied(L"Display_Copied");
StringReference MemoryCleared(L"Memory_Cleared");
StringReference DisplayCopied(L"Display_Copied");
}
} }
StandardCalculatorViewModel::StandardCalculatorViewModel() : StandardCalculatorViewModel::StandardCalculatorViewModel() :
@ -92,7 +89,9 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() :
m_localizedMemorySavedAutomationFormat(nullptr), m_localizedMemorySavedAutomationFormat(nullptr),
m_localizedMemoryItemChangedAutomationFormat(nullptr), m_localizedMemoryItemChangedAutomationFormat(nullptr),
m_localizedMemoryItemClearedAutomationFormat(nullptr), m_localizedMemoryItemClearedAutomationFormat(nullptr),
m_localizedMemoryCleared(nullptr) m_localizedMemoryCleared(nullptr),
m_localizedOpenParenthesisCountChangedAutomationFormat(nullptr),
m_localizedNoRightParenthesisAddedFormat(nullptr)
{ {
WeakReference calculatorViewModel(this); WeakReference calculatorViewModel(this);
m_calculatorDisplay.SetCallback(calculatorViewModel); m_calculatorDisplay.SetCallback(calculatorViewModel);
@ -226,6 +225,34 @@ void StandardCalculatorViewModel::SetParenthesisCount(_In_ const wstring& parent
} }
} }
void StandardCalculatorViewModel::SetOpenParenthesisCountNarratorAnnouncement()
{
String^ parenthesisCount = ((m_OpenParenthesisCount == nullptr) ? "0" : m_OpenParenthesisCount);
wstring localizedParenthesisCount = parenthesisCount->Data();
LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount);
String^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(
CalculatorResourceKeys::OpenParenthesisCountAutomationFormat,
m_localizedOpenParenthesisCountChangedAutomationFormat,
localizedParenthesisCount.c_str());
Announcement = CalculatorAnnouncement::GetOpenParenthesisCountChangedAnnouncement(announcement);
}
void StandardCalculatorViewModel::OnNoRightParenAdded()
{
SetNoParenAddedNarratorAnnouncement();
}
void StandardCalculatorViewModel::SetNoParenAddedNarratorAnnouncement()
{
String^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(
CalculatorResourceKeys::NoParenthesisAdded,
m_localizedNoRightParenthesisAddedFormat);
Announcement = CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(announcement);
}
void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionCommandType) void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionCommandType)
{ {
if (selectedExpressionCommandType == CommandType::OperandCommand) if (selectedExpressionCommandType == CommandType::OperandCommand)
@ -483,7 +510,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
if (IsOperandTextCompletelySelected) if (IsOperandTextCompletelySelected)
{ {
//Clear older text; // Clear older text;
m_selectedExpressionLastData = L""; m_selectedExpressionLastData = L"";
if (ch == L'x') if (ch == L'x')
{ {
@ -525,6 +552,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
length = m_selectedExpressionLastData->Length() + 1; length = m_selectedExpressionLastData->Length() + 1;
if (length > 50) if (length > 50)
{ {
delete [] temp;
return; return;
} }
for (; i < length; ++i) for (; i < length; ++i)
@ -550,8 +578,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
bool StandardCalculatorViewModel::IsOperator(Command cmdenum) bool StandardCalculatorViewModel::IsOperator(Command cmdenum)
{ {
if ((cmdenum == Command::Command0) || (cmdenum == Command::Command1) || (cmdenum == Command::Command2) || (cmdenum == Command::Command3) || (cmdenum == Command::Command4) || (cmdenum == Command::Command5) if ((cmdenum >= Command::Command0 && cmdenum <= Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK)
|| (cmdenum == Command::Command6) || (cmdenum == Command::Command7) || (cmdenum == Command::Command8) || (cmdenum == Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK)
|| (cmdenum == Command::CommandEXP) || (cmdenum == Command::CommandFE) || (cmdenum == Command::ModeBasic) || (cmdenum == Command::ModeProgrammer) || (cmdenum == Command::ModeScientific) || (cmdenum == Command::CommandEXP) || (cmdenum == Command::CommandFE) || (cmdenum == Command::ModeBasic) || (cmdenum == Command::ModeProgrammer) || (cmdenum == Command::ModeScientific)
|| (cmdenum == Command::CommandINV) || (cmdenum == Command::CommandCENTR) || (cmdenum == Command::CommandDEG) || (cmdenum == Command::CommandRAD) || (cmdenum == Command::CommandGRAD) || (cmdenum == Command::CommandINV) || (cmdenum == Command::CommandCENTR) || (cmdenum == Command::CommandDEG) || (cmdenum == Command::CommandRAD) || (cmdenum == Command::CommandGRAD)
|| ((cmdenum >= Command::CommandBINEDITSTART) && (cmdenum <= Command::CommandBINEDITEND))) || ((cmdenum >= Command::CommandBINEDITSTART) && (cmdenum <= Command::CommandBINEDITEND)))
@ -572,7 +599,7 @@ void StandardCalculatorViewModel::OnButtonPressed(Object^ parameter)
if (IsInError) if (IsInError)
{ {
m_standardCalculatorManager.SendCommand(Command::CommandCLEAR); m_standardCalculatorManager.SendCommand(Command::CommandCLEAR);
if (!IsRecoverableCommand((int)numOpEnum)) if (!IsRecoverableCommand((int)numOpEnum))
{ {
return; return;
@ -624,8 +651,7 @@ void StandardCalculatorViewModel::OnButtonPressed(Object^ parameter)
{ {
m_CurrentAngleType = numOpEnum; m_CurrentAngleType = numOpEnum;
} }
if ((cmdenum == Command::Command0) || (cmdenum == Command::Command1) || (cmdenum == Command::Command2) || (cmdenum == Command::Command3) || (cmdenum == Command::Command4) || (cmdenum == Command::Command5) if ((cmdenum >= Command::Command0 && cmdenum <= Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) || (cmdenum == Command::CommandEXP))
|| (cmdenum == Command::Command6) || (cmdenum == Command::Command7) || (cmdenum == Command::Command8) || (cmdenum == Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) || (cmdenum == Command::CommandEXP))
{ {
IsOperatorCommand = false; IsOperatorCommand = false;
} }
@ -835,8 +861,8 @@ void StandardCalculatorViewModel::OnPaste(String^ pastedString, ViewMode mode)
Command cmdenum = ConvertToOperatorsEnum(mappedNumOp); Command cmdenum = ConvertToOperatorsEnum(mappedNumOp);
m_standardCalculatorManager.SendCommand(cmdenum); m_standardCalculatorManager.SendCommand(cmdenum);
// The CalcEngine state machine won't allow the negate command to be sent before any // The CalcEngine state machine won't allow the negate command to be sent before any
// other digits, so instead a flag is set and the command is sent after the first appropriate // other digits, so instead a flag is set and the command is sent after the first appropriate
// command. // command.
if (sendNegate) if (sendNegate)
{ {
@ -1162,10 +1188,10 @@ Array<unsigned char>^ StandardCalculatorViewModel::Serialize()
writer->WriteInt32(data); writer->WriteInt32(data);
} }
//For ProgrammerMode // For ProgrammerMode
writer->WriteUInt32(static_cast<UINT32>(CurrentRadixType)); writer->WriteUInt32(static_cast<UINT32>(CurrentRadixType));
//Serialize commands of calculator manager // Serialize commands of calculator manager
vector<unsigned char> serializedCommand = m_standardCalculatorManager.SerializeCommands(); vector<unsigned char> serializedCommand = m_standardCalculatorManager.SerializeCommands();
writer->WriteUInt32(static_cast<UINT32>(serializedCommand.size())); writer->WriteUInt32(static_cast<UINT32>(serializedCommand.size()));
writer->WriteBytes(ref new Array<unsigned char>(serializedCommand.data(), static_cast<unsigned int>(serializedCommand.size()))); writer->WriteBytes(ref new Array<unsigned char>(serializedCommand.data(), static_cast<unsigned int>(serializedCommand.size())));
@ -1175,7 +1201,7 @@ Array<unsigned char>^ StandardCalculatorViewModel::Serialize()
Utils::SerializeCommandsAndTokens(m_tokens, m_commands, writer); Utils::SerializeCommandsAndTokens(m_tokens, m_commands, writer);
} }
//Convert viewmodel data in writer to bytes // Convert viewmodel data in writer to bytes
IBuffer^ buffer = writer->DetachBuffer(); IBuffer^ buffer = writer->DetachBuffer();
DataReader^ reader = DataReader::FromBuffer(buffer); DataReader^ reader = DataReader::FromBuffer(buffer);
Platform::Array<unsigned char>^ viewModelDataAsBytes = ref new Array<unsigned char>(buffer->Length); Platform::Array<unsigned char>^ viewModelDataAsBytes = ref new Array<unsigned char>(buffer->Length);
@ -1223,7 +1249,7 @@ void StandardCalculatorViewModel::Deserialize(Array<unsigned char>^ state)
m_standardCalculatorManager.DeSerializePrimaryDisplay(serializedPrimaryDisplay); m_standardCalculatorManager.DeSerializePrimaryDisplay(serializedPrimaryDisplay);
CurrentRadixType = reader->ReadUInt32(); CurrentRadixType = reader->ReadUInt32();
//Read command data and Deserialize // Read command data and Deserialize
UINT32 modeldatalength = reader->ReadUInt32(); UINT32 modeldatalength = reader->ReadUInt32();
Array<unsigned char>^ modelDataAsBytes = ref new Array<unsigned char>(modeldatalength); Array<unsigned char>^ modelDataAsBytes = ref new Array<unsigned char>(modeldatalength);
reader->ReadBytes(modelDataAsBytes); reader->ReadBytes(modelDataAsBytes);
@ -1242,30 +1268,30 @@ void StandardCalculatorViewModel::Deserialize(Array<unsigned char>^ state)
void StandardCalculatorViewModel::OnPropertyChanged(String^ propertyname) void StandardCalculatorViewModel::OnPropertyChanged(String^ propertyname)
{ {
if (propertyname == CalculatorViewModelProperties::IsScientific) if (propertyname == IsScientificPropertyName)
{ {
if (IsScientific) if (IsScientific)
{ {
OnButtonPressed(NumbersAndOperatorsEnum::IsScientificMode); OnButtonPressed(NumbersAndOperatorsEnum::IsScientificMode);
} }
} }
else if (propertyname == CalculatorViewModelProperties::IsProgrammer) else if (propertyname == IsProgrammerPropertyName)
{ {
if (IsProgrammer) if (IsProgrammer)
{ {
OnButtonPressed(NumbersAndOperatorsEnum::IsProgrammerMode); OnButtonPressed(NumbersAndOperatorsEnum::IsProgrammerMode);
} }
} }
else if (propertyname == CalculatorViewModelProperties::IsStandard) else if (propertyname == IsStandardPropertyName)
{ {
if (IsStandard) if (IsStandard)
{ {
OnButtonPressed(NumbersAndOperatorsEnum::IsStandardMode); OnButtonPressed(NumbersAndOperatorsEnum::IsStandardMode);
} }
} }
else if (propertyname == CalculatorViewModelProperties::DisplayValue) else if (propertyname == DisplayValuePropertyName)
{ {
RaisePropertyChanged(CalculationResultAutomationName_PropertyName); RaisePropertyChanged(CalculationResultAutomationNamePropertyName);
Announcement = GetDisplayUpdatedNarratorAnnouncement(); Announcement = GetDisplayUpdatedNarratorAnnouncement();
} }
} }
@ -1570,7 +1596,7 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory)
m_standardCalculatorManager.SendCommand(static_cast<CalculationManager::Command>(currentCommands[i])); m_standardCalculatorManager.SendCommand(static_cast<CalculationManager::Command>(currentCommands[i]));
} }
if (fromHistory) // This is for the cases where the expression is loaded from history if (fromHistory) // This is for the cases where the expression is loaded from history
{ {
// To maintain F-E state of the engine, as the last operand hasn't reached engine by now // To maintain F-E state of the engine, as the last operand hasn't reached engine by now
m_standardCalculatorManager.SendCommand(Command::CommandFE); m_standardCalculatorManager.SendCommand(Command::CommandFE);
@ -1614,7 +1640,7 @@ bool StandardCalculatorViewModel::IsOpnd(int nOpCode)
Command::CommandPNT Command::CommandPNT
}; };
for (int i = 0; i < ARRAYSIZE(opnd); i++) for (unsigned int i = 0; i < size(opnd); i++)
{ {
if (nOpCode == static_cast<int>(opnd[i])) if (nOpCode == static_cast<int>(opnd[i]))
{ {
@ -1645,7 +1671,7 @@ bool StandardCalculatorViewModel::IsUnaryOp(int nOpCode)
Command::CommandCUB Command::CommandCUB
}; };
for (int i = 0; i < ARRAYSIZE(unaryOp); i++) for (unsigned int i = 0; i < size(unaryOp); i++)
{ {
if (nOpCode == static_cast<int>(unaryOp[i])) if (nOpCode == static_cast<int>(unaryOp[i]))
{ {
@ -1672,7 +1698,7 @@ bool StandardCalculatorViewModel::IsTrigOp(int nOpCode)
Command::CommandATAN Command::CommandATAN
}; };
for (int i = 0; i < ARRAYSIZE(trigOp); i++) for (unsigned int i = 0; i < size(trigOp); i++)
{ {
if (nOpCode == static_cast<int>(trigOp[i])) if (nOpCode == static_cast<int>(trigOp[i]))
{ {
@ -1695,7 +1721,7 @@ bool StandardCalculatorViewModel::IsBinOp(int nOpCode)
Command::CommandPWR Command::CommandPWR
}; };
for (int i = 0; i < ARRAYSIZE(binOp); i++) for (unsigned int i = 0; i < size(binOp); i++)
{ {
if (nOpCode == static_cast<int>(binOp[i])) if (nOpCode == static_cast<int>(binOp[i]))
{ {
@ -1729,7 +1755,7 @@ bool StandardCalculatorViewModel::IsRecoverableCommand(int nOpCode)
Command::CommandF Command::CommandF
}; };
for (int i = 0; i < ARRAYSIZE(recoverableCommands); i++) for (unsigned int i = 0; i < size(recoverableCommands); i++)
{ {
if (nOpCode == static_cast<int>(recoverableCommands[i])) if (nOpCode == static_cast<int>(recoverableCommands[i]))
{ {
@ -1947,7 +1973,7 @@ void StandardCalculatorViewModel::UpdatecommandsInRecordingMode()
} }
else else
{ {
//reset all vars // Reset all vars
isDecimal = false; isDecimal = false;
isNegative = false; isNegative = false;
isExpMode = false; isExpMode = false;

View file

@ -31,12 +31,6 @@ namespace CalculatorApp
#define ASCII_0 48 #define ASCII_0 48
public delegate void HideMemoryClickedHandler(); public delegate void HideMemoryClickedHandler();
public delegate void ProgModeRadixChangeHandler(); public delegate void ProgModeRadixChangeHandler();
namespace CalculatorViewModelProperties
{
extern Platform::StringReference IsMemoryEmpty;
extern Platform::StringReference IsInError;
extern Platform::StringReference BinaryDisplayValue;
}
[Windows::UI::Xaml::Data::Bindable] [Windows::UI::Xaml::Data::Bindable]
public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
@ -51,14 +45,14 @@ namespace CalculatorApp
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayValue);
OBSERVABLE_PROPERTY_RW(HistoryViewModel^, HistoryVM); OBSERVABLE_PROPERTY_RW(HistoryViewModel^, HistoryVM);
OBSERVABLE_PROPERTY_RW(bool, IsInError); OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError);
OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand); OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand);
OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayStringExpression); OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayStringExpression);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector<Common::DisplayExpressionToken^>^, ExpressionTokens); OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector<Common::DisplayExpressionToken^>^, ExpressionTokens);
OBSERVABLE_PROPERTY_RW(Platform::String^, DecimalDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, DecimalDisplayValue);
OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue);
OBSERVABLE_PROPERTY_RW(Platform::String^, OctalDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, OctalDisplayValue);
OBSERVABLE_PROPERTY_RW(Platform::String^, BinaryDisplayValue); OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, BinaryDisplayValue);
OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue_AutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue_AutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String^, DecDisplayValue_AutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, DecDisplayValue_AutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String^, OctDisplayValue_AutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, OctDisplayValue_AutomationName);
@ -69,19 +63,19 @@ namespace CalculatorApp
OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsCurrentViewPinned); OBSERVABLE_PROPERTY_RW(bool, IsCurrentViewPinned);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector<MemoryItemViewModel^>^, MemorizedNumbers); OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector<MemoryItemViewModel^>^, MemorizedNumbers);
OBSERVABLE_PROPERTY_RW(bool, IsMemoryEmpty); OBSERVABLE_NAMED_PROPERTY_RW(bool, IsMemoryEmpty);
OBSERVABLE_PROPERTY_RW(bool, IsFToEChecked); OBSERVABLE_PROPERTY_RW(bool, IsFToEChecked);
OBSERVABLE_PROPERTY_RW(bool, IsFToEEnabled); OBSERVABLE_PROPERTY_RW(bool, IsFToEEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsHyperbolicChecked); OBSERVABLE_PROPERTY_RW(bool, IsHyperbolicChecked);
OBSERVABLE_PROPERTY_RW(bool, AreHEXButtonsEnabled); OBSERVABLE_PROPERTY_RW(bool, AreHEXButtonsEnabled);
NAMED_OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationResultAutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationResultAutomationName);
NAMED_OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationExpressionAutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationExpressionAutomationName);
OBSERVABLE_PROPERTY_RW(bool, IsShiftProgrammerChecked); OBSERVABLE_PROPERTY_RW(bool, IsShiftProgrammerChecked);
OBSERVABLE_PROPERTY_RW(bool, IsQwordEnabled); OBSERVABLE_PROPERTY_RW(bool, IsQwordEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsDwordEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDwordEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsWordEnabled); OBSERVABLE_PROPERTY_RW(bool, IsWordEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsByteEnabled); OBSERVABLE_PROPERTY_RW(bool, IsByteEnabled);
OBSERVABLE_PROPERTY_RW(Platform::String^, OpenParenthesisCount); OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, OpenParenthesisCount);
OBSERVABLE_PROPERTY_RW(int, CurrentRadixType); OBSERVABLE_PROPERTY_RW(int, CurrentRadixType);
OBSERVABLE_PROPERTY_RW(bool, AreTokensUpdated); OBSERVABLE_PROPERTY_RW(bool, AreTokensUpdated);
OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled); OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled);
@ -263,7 +257,7 @@ namespace CalculatorApp
property Platform::String^ LeftParenthesisAutomationName property Platform::String^ LeftParenthesisAutomationName
{ {
Platform::String^ get() Platform::String^ get()
{ {
return GetLeftParenthesisAutomationName(); return GetLeftParenthesisAutomationName();
} }
@ -276,7 +270,7 @@ namespace CalculatorApp
NumbersAndOperatorsEnum MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate); NumbersAndOperatorsEnum MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate);
//Memory feature related methods. They are internal because they need to called from the MainPage code-behind // Memory feature related methods. They are internal because they need to called from the MainPage code-behind
void OnMemoryButtonPressed(); void OnMemoryButtonPressed();
void OnMemoryItemPressed(Platform::Object^ memoryItemPosition); void OnMemoryItemPressed(Platform::Object^ memoryItemPosition);
void OnMemoryAdd(Platform::Object^ memoryItemPosition); void OnMemoryAdd(Platform::Object^ memoryItemPosition);
@ -290,6 +284,9 @@ namespace CalculatorApp
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); 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);
void SetHistoryExpressionDisplay(_Inout_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const &tokens, _Inout_ std::shared_ptr<CalculatorVector <std::shared_ptr<IExpressionCommand>>> const &commands); void SetHistoryExpressionDisplay(_Inout_ std::shared_ptr<CalculatorVector<std::pair<std::wstring, int>>> const &tokens, _Inout_ std::shared_ptr<CalculatorVector <std::shared_ptr<IExpressionCommand>>> const &commands);
void SetParenthesisCount(_In_ const std::wstring& parenthesisCount); void SetParenthesisCount(_In_ const std::wstring& parenthesisCount);
void SetOpenParenthesisCountNarratorAnnouncement();
void OnNoRightParenAdded();
void SetNoParenAddedNarratorAnnouncement();
void OnMaxDigitsReached(); void OnMaxDigitsReached();
void OnBinaryOperatorReceived(); void OnBinaryOperatorReceived();
void OnMemoryItemChanged(unsigned int indexOfMemory); void OnMemoryItemChanged(unsigned int indexOfMemory);
@ -337,6 +334,8 @@ namespace CalculatorApp
Platform::String^ m_localizedMemoryItemChangedAutomationFormat; Platform::String^ m_localizedMemoryItemChangedAutomationFormat;
Platform::String^ m_localizedMemoryItemClearedAutomationFormat; Platform::String^ m_localizedMemoryItemClearedAutomationFormat;
Platform::String^ m_localizedMemoryCleared; Platform::String^ m_localizedMemoryCleared;
Platform::String^ m_localizedOpenParenthesisCountChangedAutomationFormat;
Platform::String^ m_localizedNoRightParenthesisAddedFormat;
bool m_pinned; bool m_pinned;
bool m_isOperandEnabled; bool m_isOperandEnabled;

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
#include "pch.h" #include "pch.h"
@ -53,48 +53,40 @@ constexpr size_t SELECTED_TARGET_UNIT = 2;
// x millisecond delay before we consider conversion to be final // x millisecond delay before we consider conversion to be final
constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000; constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000;
const wregex regexTrimSpacesStart = wregex(L"^\\s+");
const wregex regexTrimSpacesEnd = wregex(L"\\s+$");
namespace CalculatorApp::ViewModel namespace
{ {
namespace UnitConverterViewModelProperties StringReference CurrentCategoryPropertyName(L"CurrentCategory");
{ StringReference Unit1AutomationNamePropertyName(L"Unit1AutomationName");
StringReference CurrentCategory(L"CurrentCategory"); StringReference Unit2AutomationNamePropertyName(L"Unit2AutomationName");
StringReference Unit1(L"Unit1"); StringReference Unit1PropertyName(L"Unit1");
StringReference Unit2(L"Unit2"); StringReference Unit2PropertyName(L"Unit2");
StringReference Value1Active(L"Value1Active"); StringReference Value1PropertyName(L"Value1");
StringReference Value2Active(L"Value2Active"); StringReference Value2PropertyName(L"Value2");
StringReference Value1(L"Value1"); StringReference Value1ActivePropertyName(L"Value1Active");
StringReference Value2(L"Value2"); StringReference Value2ActivePropertyName(L"Value2Active");
StringReference Value1AutomationName(L"Value1AutomationName"); StringReference Value1AutomationNamePropertyName(L"Value1AutomationName");
StringReference Value2AutomationName(L"Value2AutomationName"); StringReference Value2AutomationNamePropertyName(L"Value2AutomationName");
StringReference SupplementaryVisibility(L"SupplementaryVisibility"); StringReference CurrencySymbol1PropertyName(L"CurrencySymbol1");
StringReference SupplementaryResults(L"SupplementaryResults"); StringReference CurrencySymbol2PropertyName(L"CurrencySymbol2");
StringReference Unit1AutomationName(L"Unit1AutomationName"); StringReference CurrencySymbolVisibilityPropertyName(L"CurrencySymbolVisibility");
StringReference Unit2AutomationName(L"Unit2AutomationName"); StringReference SupplementaryVisibilityPropertyName(L"SupplementaryVisibility");
StringReference CurrencySymbol1(L"CurrencySymbol1"); }
StringReference CurrencySymbol2(L"CurrencySymbol2");
StringReference CurrencySymbolVisibility(L"CurrencySymbolVisibility");
StringReference CurrencyRatioEquality(L"CurrencyRatioEquality");
StringReference CurrencyRatioEqualityAutomationName(L"CurrencyRatioEqualityAutomationName");
StringReference NetworkBehavior(L"NetworkBehavior");
StringReference CurrencyDataLoadFailed(L"CurrencyDataLoadFailed");
StringReference CurrencyDataIsWeekOld(L"CurrencyDataIsWeekOld");
StringReference IsCurrencyLoadingVisible(L"IsCurrencyLoadingVisible");
}
namespace UnitConverterResourceKeys namespace CalculatorApp::ViewModel::UnitConverterResourceKeys
{ {
StringReference ValueFromFormat(L"Format_ValueFrom"); StringReference ValueFromFormat(L"Format_ValueFrom");
StringReference ValueFromDecimalFormat(L"Format_ValueFrom_Decimal"); StringReference ValueFromDecimalFormat(L"Format_ValueFrom_Decimal");
StringReference ValueToFormat(L"Format_ValueTo"); StringReference ValueToFormat(L"Format_ValueTo");
StringReference ConversionResultFormat(L"Format_ConversionResult"); StringReference ConversionResultFormat(L"Format_ConversionResult");
StringReference InputUnit_Name(L"InputUnit_Name"); StringReference InputUnit_Name(L"InputUnit_Name");
StringReference OutputUnit_Name(L"OutputUnit_Name"); StringReference OutputUnit_Name(L"OutputUnit_Name");
StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached"); StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached");
StringReference UpdatingCurrencyRates(L"UpdatingCurrencyRates"); StringReference UpdatingCurrencyRates(L"UpdatingCurrencyRates");
StringReference CurrencyRatesUpdated(L"CurrencyRatesUpdated"); StringReference CurrencyRatesUpdated(L"CurrencyRatesUpdated");
StringReference CurrencyRatesUpdateFailed(L"CurrencyRatesUpdateFailed"); StringReference CurrencyRatesUpdateFailed(L"CurrencyRatesUpdateFailed");
}
} }
UnitConverterViewModel::UnitConverterViewModel(const shared_ptr<UCM::IUnitConverter>& model) : UnitConverterViewModel::UnitConverterViewModel(const shared_ptr<UCM::IUnitConverter>& model) :
@ -142,7 +134,7 @@ UnitConverterViewModel::UnitConverterViewModel(const shared_ptr<UCM::IUnitConver
m_currencyFormatter->Mode = CurrencyFormatterMode::UseCurrencyCode; m_currencyFormatter->Mode = CurrencyFormatterMode::UseCurrencyCode;
m_currencyFormatter->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown); m_currencyFormatter->ApplyRoundingForCurrency(RoundingAlgorithm::RoundHalfDown);
m_currencyMaxFractionDigits = m_currencyFormatter->FractionDigits; m_currencyMaxFractionDigits = m_currencyFormatter->FractionDigits;
auto resourceLoader = AppResourceProvider::GetInstance(); auto resourceLoader = AppResourceProvider::GetInstance();
m_localizedValueFromFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueFromFormat); m_localizedValueFromFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueFromFormat);
m_localizedValueToFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueToFormat); m_localizedValueToFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueToFormat);
@ -202,12 +194,10 @@ void UnitConverterViewModel::BuildUnitList(const vector<UCM::Unit>& modelUnitLis
m_Units->Clear(); m_Units->Clear();
for (const UCM::Unit& modelUnit : modelUnitList) for (const UCM::Unit& modelUnit : modelUnitList)
{ {
if (modelUnit.isWhimsical) if (!modelUnit.isWhimsical)
{ {
continue; m_Units->Append(ref new Unit(modelUnit));
} }
m_Units->Append(ref new Unit(modelUnit));
} }
if (m_Units->Size == 0) if (m_Units->Size == 0)
@ -257,7 +247,7 @@ void UnitConverterViewModel::OnUnitChanged(Object^ parameter)
void UnitConverterViewModel::OnSwitchActive(Platform::Object^ unused) void UnitConverterViewModel::OnSwitchActive(Platform::Object^ unused)
{ {
// this can be false if this switch occurs without the user having explicitly updated any strings // this can be false if this switch occurs without the user having explicitly updated any strings
// (for example, during deserialization). We only want to try this cleanup if there's actually // (for example, during deserialization). We only want to try this cleanup if there's actually
// something to clean up. // something to clean up.
if (m_relocalizeStringOnSwitch) if (m_relocalizeStringOnSwitch)
@ -279,10 +269,10 @@ void UnitConverterViewModel::OnSwitchActive(Platform::Object^ unused)
m_valueFromUnlocalized.swap(m_valueToUnlocalized); m_valueFromUnlocalized.swap(m_valueToUnlocalized);
Utils::Swap(&m_localizedValueFromFormat, &m_localizedValueToFormat); Utils::Swap(&m_localizedValueFromFormat, &m_localizedValueToFormat);
Utils::Swap(&m_Unit1AutomationName, &m_Unit2AutomationName); Utils::Swap(&m_Unit1AutomationName, &m_Unit2AutomationName);
RaisePropertyChanged(UnitConverterViewModelProperties::Unit1AutomationName); RaisePropertyChanged(Unit1AutomationNamePropertyName);
RaisePropertyChanged(UnitConverterViewModelProperties::Unit2AutomationName); RaisePropertyChanged(Unit2AutomationNamePropertyName);
m_isInputBlocked = false; m_isInputBlocked = false;
m_model->SwitchActive(m_valueFromUnlocalized); m_model->SwitchActive(m_valueFromUnlocalized);
@ -324,7 +314,7 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str
if (allowPartialStrings) if (allowPartialStrings)
{ {
// allow "in progress" strings, like "3." that occur during the composition of // allow "in progress" strings, like "3." that occur during the composition of
// a final number. Without this, when typing the three characters in "3.2" // a final number. Without this, when typing the three characters in "3.2"
// you don't see the decimal point when typing it, you only see it once you've finally // you don't see the decimal point when typing it, you only see it once you've finally
// typed a post-decimal digit. // typed a post-decimal digit.
@ -341,17 +331,22 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str
{ {
wstring currencyResult = m_currencyFormatter->Format(stod(stringToLocalize))->Data(); wstring currencyResult = m_currencyFormatter->Format(stod(stringToLocalize))->Data();
wstring currencyCode = m_currencyFormatter->Currency->Data(); wstring currencyCode = m_currencyFormatter->Currency->Data();
// CurrencyFormatter always includes LangCode or Symbol. Make it include LangCode // CurrencyFormatter always includes LangCode or Symbol. Make it include LangCode
// because this includes a non-breaking space. Remove the LangCode. // because this includes a non-breaking space. Remove the LangCode.
auto pos = currencyResult.find(currencyCode); auto pos = currencyResult.find(currencyCode);
if (pos != wstring::npos) if (pos != wstring::npos)
{ {
currencyResult.erase(pos, currencyCode.length()); currencyResult.erase(pos, currencyCode.length());
pos = currencyResult.find(L'\u00a0'); // non-breaking space std::wsmatch sm;
if (pos != wstring::npos) if (regex_search(currencyResult, sm, regexTrimSpacesStart))
{ {
currencyResult.erase(pos, 1); currencyResult.erase(sm.prefix().length(), sm.length());
}
if (regex_search(currencyResult, sm, regexTrimSpacesEnd))
{
currencyResult.erase(sm.prefix().length(), sm.length());
} }
} }
@ -367,7 +362,7 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str
if (hasDecimal) if (hasDecimal)
{ {
// Since the output from GetLocaleInfoEx() and DecimalFormatter are differing for decimal string // Since the output from GetLocaleInfoEx() and DecimalFormatter are differing for decimal string
// we are adding the below work-around of editing the string returned by DecimalFormatter // we are adding the below work-around of editing the string returned by DecimalFormatter
// and replacing the decimal separator with the one returned by GetLocaleInfoEx() // and replacing the decimal separator with the one returned by GetLocaleInfoEx()
String^ formattedSampleString = m_decimalFormatter->Format(stod("1.1")); String^ formattedSampleString = m_decimalFormatter->Format(stod("1.1"));
wstring formattedSampleWString = wstring(formattedSampleString->Data()); wstring formattedSampleWString = wstring(formattedSampleString->Data());
@ -378,7 +373,7 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str
{ {
resultWithDecimal.replace(pos, 1, &m_decimalSeparator); resultWithDecimal.replace(pos, 1, &m_decimalSeparator);
} }
// Copy back the edited string to the result // Copy back the edited string to the result
result = ref new String(resultWithDecimal.c_str()); result = ref new String(resultWithDecimal.c_str());
} }
@ -479,7 +474,7 @@ void UnitConverterViewModel::OnButtonPressed(Platform::Object^ parameter)
NumbersAndOperatorsEnum numOpEnum = CalculatorButtonPressedEventArgs::GetOperationFromCommandParameter(parameter); NumbersAndOperatorsEnum numOpEnum = CalculatorButtonPressedEventArgs::GetOperationFromCommandParameter(parameter);
UCM::Command command = CommandFromButtonId(numOpEnum); UCM::Command command = CommandFromButtonId(numOpEnum);
//Don't clear the display if combo box is open and escape is pressed // Don't clear the display if combo box is open and escape is pressed
if (command == UCM::Command::Clear && IsDropDownOpen) if (command == UCM::Command::Clear && IsDropDownOpen)
{ {
return; return;
@ -556,13 +551,13 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop)
{ {
static bool isCategoryChanging = false; static bool isCategoryChanging = false;
if (prop->Equals(UnitConverterViewModelProperties::CurrentCategory)) if (prop == CurrentCategoryPropertyName)
{ {
isCategoryChanging = true; isCategoryChanging = true;
CategoryChanged->Execute(nullptr); CategoryChanged->Execute(nullptr);
isCategoryChanging = false; isCategoryChanging = false;
} }
else if (prop->Equals(UnitConverterViewModelProperties::Unit1) || prop->Equals(UnitConverterViewModelProperties::Unit2)) else if (prop == Unit1PropertyName || prop == Unit2PropertyName)
{ {
// Category changes will handle updating units after they've both been updated. // Category changes will handle updating units after they've both been updated.
// This event should only be used to update units from explicit user interaction. // This event should only be used to update units from explicit user interaction.
@ -571,7 +566,7 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop)
UnitChanged->Execute(nullptr); UnitChanged->Execute(nullptr);
} }
// Get the localized automation name for each CalculationResults field // Get the localized automation name for each CalculationResults field
if (prop->Equals(UnitConverterViewModelProperties::Unit1)) if (prop == Unit1PropertyName)
{ {
UpdateValue1AutomationName(); UpdateValue1AutomationName();
} }
@ -580,15 +575,15 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop)
UpdateValue2AutomationName(); UpdateValue2AutomationName();
} }
} }
else if (prop->Equals(UnitConverterViewModelProperties::Value1)) else if (prop == Value1PropertyName)
{ {
UpdateValue1AutomationName(); UpdateValue1AutomationName();
} }
else if (prop->Equals(UnitConverterViewModelProperties::Value2)) else if (prop == Value2PropertyName)
{ {
UpdateValue2AutomationName(); UpdateValue2AutomationName();
} }
else if (prop->Equals(UnitConverterViewModelProperties::Value1Active) || prop->Equals(UnitConverterViewModelProperties::Value2Active)) else if (prop == Value1ActivePropertyName || prop == Value2ActivePropertyName)
{ {
// if one of the values is activated, and as a result both are true, it means // if one of the values is activated, and as a result both are true, it means
// that we're trying to switch. // that we're trying to switch.
@ -600,11 +595,11 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop)
UpdateValue1AutomationName(); UpdateValue1AutomationName();
UpdateValue2AutomationName(); UpdateValue2AutomationName();
} }
else if (prop->Equals(UnitConverterViewModelProperties::SupplementaryResults)) else if (prop == SupplementaryResultsPropertyName)
{ {
RaisePropertyChanged(UnitConverterViewModelProperties::SupplementaryVisibility); RaisePropertyChanged(SupplementaryVisibilityPropertyName);
} }
else if (prop->Equals(UnitConverterViewModelProperties::Value1AutomationName)) else if (prop == Value1AutomationNamePropertyName)
{ {
m_isValue1Updating = false; m_isValue1Updating = false;
if (!m_isValue2Updating) if (!m_isValue2Updating)
@ -612,7 +607,7 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop)
AnnounceConversionResult(); AnnounceConversionResult();
} }
} }
else if (prop->Equals(UnitConverterViewModelProperties::Value2AutomationName)) else if (prop == Value2AutomationNamePropertyName)
{ {
m_isValue2Updating = false; m_isValue2Updating = false;
if (!m_isValue1Updating) if (!m_isValue1Updating)
@ -620,9 +615,9 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop)
AnnounceConversionResult(); AnnounceConversionResult();
} }
} }
else if (prop->Equals(UnitConverterViewModelProperties::CurrencySymbol1) || prop->Equals(UnitConverterViewModelProperties::CurrencySymbol2)) else if (prop == CurrencySymbol1PropertyName || prop == CurrencySymbol2PropertyName)
{ {
RaisePropertyChanged(UnitConverterViewModelProperties::CurrencySymbolVisibility); RaisePropertyChanged(CurrencySymbolVisibilityPropertyName);
} }
} }
@ -643,10 +638,8 @@ String^ UnitConverterViewModel::Serialize()
String^ serializedData = ref new String(wstring(out.str()).c_str()); String^ serializedData = ref new String(wstring(out.str()).c_str());
return serializedData; return serializedData;
} }
else
{ return nullptr;
return nullptr;
}
} }
void UnitConverterViewModel::Deserialize(Platform::String^ state) void UnitConverterViewModel::Deserialize(Platform::String^ state)
@ -674,7 +667,7 @@ void UnitConverterViewModel::Deserialize(Platform::String^ state)
RaisePropertyChanged(nullptr); // Update since all props have been updated. RaisePropertyChanged(nullptr); // Update since all props have been updated.
} }
//Saving User Preferences of Category and Associated-Units across Sessions. // Saving User Preferences of Category and Associated-Units across Sessions.
void UnitConverterViewModel::SaveUserPreferences() void UnitConverterViewModel::SaveUserPreferences()
{ {
if (UnitsAreValid()) if (UnitsAreValid())
@ -695,7 +688,7 @@ void UnitConverterViewModel::SaveUserPreferences()
} }
} }
//Restoring User Preferences of Category and Associated-Units. // Restoring User Preferences of Category and Associated-Units.
void UnitConverterViewModel::RestoreUserPreferences() void UnitConverterViewModel::RestoreUserPreferences()
{ {
if (!IsCurrencyCurrentCategory) if (!IsCurrencyCurrentCategory)
@ -849,7 +842,7 @@ void UnitConverterViewModel::RefreshSupplementaryResults()
} }
m_cacheMutex.unlock(); m_cacheMutex.unlock();
RaisePropertyChanged(UnitConverterViewModelProperties::SupplementaryResults); RaisePropertyChanged(SupplementaryResultsPropertyName);
//EventWriteConverterSupplementaryResultsUpdated(); //EventWriteConverterSupplementaryResultsUpdated();
} }
@ -879,14 +872,11 @@ void UnitConverterViewModel::UpdateInputBlocked(_In_ const wstring& currencyInpu
{ {
// currencyInput is in en-US and has the default decimal separator, so this is safe to do. // currencyInput is in en-US and has the default decimal separator, so this is safe to do.
auto posOfDecimal = currencyInput.find(L'.'); auto posOfDecimal = currencyInput.find(L'.');
m_isInputBlocked = false;
if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory) if (posOfDecimal != wstring::npos && IsCurrencyCurrentCategory)
{ {
m_isInputBlocked = (posOfDecimal + static_cast<size_t>(m_currencyMaxFractionDigits) + 1 == currencyInput.length()); m_isInputBlocked = (posOfDecimal + static_cast<size_t>(m_currencyMaxFractionDigits) + 1 == currencyInput.length());
} }
else
{
m_isInputBlocked = false;
}
} }
NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId( NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(
@ -973,7 +963,7 @@ void UnitConverterViewModel::OnPaste(String^ stringToPaste, ViewMode mode)
{ {
if (isFirstLegalChar) if (isFirstLegalChar)
{ {
// Send Clear before sending something that will actually apply // Send Clear before sending something that will actually apply
// to the field. // to the field.
m_model->SendCommand(UCM::Command::Clear); m_model->SendCommand(UCM::Command::Clear);
isFirstLegalChar = false; isFirstLegalChar = false;
@ -988,7 +978,7 @@ void UnitConverterViewModel::OnPaste(String^ stringToPaste, ViewMode mode)
} }
// Negate is only allowed if it's the first legal character, which is handled above. // Negate is only allowed if it's the first legal character, which is handled above.
if (NumbersAndOperatorsEnum::None != op && NumbersAndOperatorsEnum::Negate != op) if (NumbersAndOperatorsEnum::Negate != op)
{ {
UCM::Command cmd = CommandFromButtonId(op); UCM::Command cmd = CommandFromButtonId(op);
m_model->SendCommand(cmd); m_model->SendCommand(cmd);

View file

@ -19,7 +19,7 @@ namespace CalculatorApp
public ref class Category sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged public ref class Category sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{ {
internal: internal:
Category(const UnitConversionManager::Category& category) : Category(const UnitConversionManager::Category& category) :
m_original(category) m_original(category)
{ } { }
@ -52,7 +52,7 @@ namespace CalculatorApp
public ref class Unit sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged public ref class Unit sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{ {
internal: internal:
Unit(const UnitConversionManager::Unit& unit) : Unit(const UnitConversionManager::Unit& unit) :
m_original(unit) m_original(unit)
{ } { }
@ -138,32 +138,13 @@ namespace CalculatorApp
return ref new Activatable<TActivatable>(activatable); return ref new Activatable<TActivatable>(activatable);
} }
namespace UnitConverterViewModelProperties
{
extern Platform::StringReference CurrentCategory;
extern Platform::StringReference Unit1;
extern Platform::StringReference Unit2;
extern Platform::StringReference Value1Active;
extern Platform::StringReference Value2Active;
extern Platform::StringReference SupplementaryVisibility;
extern Platform::StringReference SupplementaryResults;
extern Platform::StringReference CurrencySymbol1;
extern Platform::StringReference CurrencySymbol2;
extern Platform::StringReference CurrencySymbolVisibility;
extern Platform::StringReference CurrencyRatioEquality;
extern Platform::StringReference NetworkBehavior;
extern Platform::StringReference CurrencyDataLoadFailed;
extern Platform::StringReference CurrencyDataIsWeekOld;
extern Platform::StringReference IsCurrencyLoadingVisible;
}
[Windows::UI::Xaml::Data::Bindable] [Windows::UI::Xaml::Data::Bindable]
public ref class UnitConverterViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged public ref class UnitConverterViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{ {
internal: internal:
UnitConverterViewModel(const std::shared_ptr<UnitConversionManager::IUnitConverter>& model); UnitConverterViewModel(const std::shared_ptr<UnitConversionManager::IUnitConverter>& model);
public: public:
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<Category^>^, Categories); OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<Category^>^, Categories);
@ -176,7 +157,7 @@ namespace CalculatorApp
OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencySymbol2); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencySymbol2);
OBSERVABLE_PROPERTY_RW(Unit^, Unit2); OBSERVABLE_PROPERTY_RW(Unit^, Unit2);
OBSERVABLE_PROPERTY_RW(Platform::String^, Value2); OBSERVABLE_PROPERTY_RW(Platform::String^, Value2);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<SupplementaryResult^>^, SupplementaryResults); OBSERVABLE_NAMED_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<SupplementaryResult^>^, SupplementaryResults);
OBSERVABLE_PROPERTY_RW(bool, Value1Active); OBSERVABLE_PROPERTY_RW(bool, Value1Active);
OBSERVABLE_PROPERTY_RW(bool, Value2Active); OBSERVABLE_PROPERTY_RW(bool, Value2Active);
OBSERVABLE_PROPERTY_RW(Platform::String^, Value1AutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, Value1AutomationName);
@ -187,14 +168,14 @@ namespace CalculatorApp
OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsDropDownOpen); OBSERVABLE_PROPERTY_RW(bool, IsDropDownOpen);
OBSERVABLE_PROPERTY_RW(bool, IsDropDownEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDropDownEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsCurrencyLoadingVisible); OBSERVABLE_NAMED_PROPERTY_RW(bool, IsCurrencyLoadingVisible);
OBSERVABLE_PROPERTY_RW(bool, IsCurrencyCurrentCategory); OBSERVABLE_PROPERTY_RW(bool, IsCurrencyCurrentCategory);
OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyRatioEquality); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyRatioEquality);
OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyRatioEqualityAutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyRatioEqualityAutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyTimestamp); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyTimestamp);
OBSERVABLE_PROPERTY_RW(CalculatorApp::NetworkAccessBehavior, NetworkBehavior); OBSERVABLE_NAMED_PROPERTY_RW(CalculatorApp::NetworkAccessBehavior, NetworkBehavior);
OBSERVABLE_PROPERTY_RW(bool, CurrencyDataLoadFailed); OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataLoadFailed);
OBSERVABLE_PROPERTY_RW(bool, CurrencyDataIsWeekOld); OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataIsWeekOld);
property Windows::UI::Xaml::Visibility SupplementaryVisibility property Windows::UI::Xaml::Visibility SupplementaryVisibility
{ {
@ -224,7 +205,7 @@ namespace CalculatorApp
COMMAND_FOR_METHOD(PasteCommand, UnitConverterViewModel::OnPasteCommand); COMMAND_FOR_METHOD(PasteCommand, UnitConverterViewModel::OnPasteCommand);
void AnnounceConversionResult(); void AnnounceConversionResult();
internal: internal:
void ResetView(); void ResetView();
void PopulateData(); void PopulateData();
@ -242,8 +223,8 @@ namespace CalculatorApp
void UpdateValue2AutomationName(); void UpdateValue2AutomationName();
Platform::String^ Serialize(); Platform::String^ Serialize();
void Deserialize(Platform::String^ state); void Deserialize(Platform::String^ state);
//Saving And Restoring User Preferences of Category and Associated-Units across Sessions. // Saving And Restoring User Preferences of Category and Associated-Units across Sessions.
void SaveUserPreferences(); void SaveUserPreferences();
void RestoreUserPreferences(); void RestoreUserPreferences();
@ -360,9 +341,9 @@ namespace CalculatorApp
UnitConverterVMCallback(UnitConverterViewModel^ viewModel) : m_viewModel(viewModel) UnitConverterVMCallback(UnitConverterViewModel^ viewModel) : m_viewModel(viewModel)
{} {}
void DisplayCallback(const std::wstring& from, const std::wstring& to) override void DisplayCallback(const std::wstring& from, const std::wstring& to) override
{ {
m_viewModel->UpdateDisplay(from, to); m_viewModel->UpdateDisplay(from, to);
} }
void SuggestedValueCallback( void SuggestedValueCallback(

View file

@ -10,6 +10,10 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
// Windows headers define min/max macros.
// Disable it for project code.
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <collection.h> #include <collection.h>
@ -26,7 +30,7 @@
#include <sstream> #include <sstream>
#include <concrt.h> #include <concrt.h>
#include <regex> #include <regex>
#include <iterator>
// C++\WinRT Headers // C++\WinRT Headers
#include "winrt/base.h" #include "winrt/base.h"
#include "winrt/Windows.Foundation.Diagnostics.h" #include "winrt/Windows.Foundation.Diagnostics.h"

View file

@ -9,7 +9,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcManager", "CalcManager\
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A5DF651-B8A1-45CA-9135-964A6FC7F5D1}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A5DF651-B8A1-45CA-9135-964A6FC7F5D1}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
nuget.config = nuget.config nuget.config = nuget.config
EndProjectSection EndProjectSection
EndProject EndProject

View file

@ -38,7 +38,7 @@
<Paragraph> <Paragraph>
<Run x:Name="AboutFlyoutVersion"/> <Run x:Name="AboutFlyoutVersion"/>
<LineBreak/> <LineBreak/>
<Run x:Uid="AboutControlCopyright"/> <Run x:Name="AboutControlCopyrightRun"/>
</Paragraph> </Paragraph>
</RichTextBlock> </RichTextBlock>
<HyperlinkButton x:Name="AboutFlyoutEULA" <HyperlinkButton x:Name="AboutFlyoutEULA"

View file

@ -8,6 +8,7 @@
#include "CalcViewModel/Common/LocalizationStringUtil.h" #include "CalcViewModel/Common/LocalizationStringUtil.h"
#include "CalcViewModel/Common/TraceLogger.h" #include "CalcViewModel/Common/TraceLogger.h"
using namespace std;
using namespace CalculatorApp; using namespace CalculatorApp;
using namespace CalculatorApp::Common; using namespace CalculatorApp::Common;
using namespace Platform; using namespace Platform;
@ -19,6 +20,10 @@ using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Data;
#ifndef BUILD_YEAR
#define BUILD_YEAR 2019
#endif
AboutFlyout::AboutFlyout() AboutFlyout::AboutFlyout()
{ {
auto locService = LocalizationService::GetInstance(); auto locService = LocalizationService::GetInstance();
@ -31,6 +36,10 @@ AboutFlyout::AboutFlyout()
this->SetVersionString(); this->SetVersionString();
Header->Text = resourceLoader.GetResourceString("AboutButton/Content"); Header->Text = resourceLoader.GetResourceString("AboutButton/Content");
auto copyrightText = LocalizationStringUtil::GetLocalizedString(resourceLoader.GetResourceString("AboutControlCopyright")->Data(), to_wstring(BUILD_YEAR).c_str());
AboutControlCopyrightRun->Text = ref new String(copyrightText.c_str());
} }
void AboutFlyout::FeedbackButton_Click(_In_ Object^ sender, _In_ RoutedEventArgs^ e) void AboutFlyout::FeedbackButton_Click(_In_ Object^ sender, _In_ RoutedEventArgs^ e)

View file

@ -371,12 +371,13 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ActiveStates"> <VisualStateGroup x:Name="ActiveStates">
<VisualState x:Name="Active"/> <VisualState x:Name="Active">
<VisualState x:Name="Normal">
<VisualState.Setters> <VisualState.Setters>
<Setter Target="normalOutput.FontWeight" Value="Light"/> <Setter Target="normalOutput.FontWeight" Value="SemiBold"/>
<Setter Target="normalOutput.IsTextSelectionEnabled" Value="True"/>
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
<VisualState x:Name="Normal"/>
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
<ScrollViewer x:Name="textContainer" <ScrollViewer x:Name="textContainer"
@ -390,7 +391,7 @@
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
FontSize="{TemplateBinding FontSize}" FontSize="{TemplateBinding FontSize}"
FontWeight="SemiBold" FontWeight="Light"
AutomationProperties.AccessibilityView="Raw" AutomationProperties.AccessibilityView="Raw"
Text="{TemplateBinding DisplayValue}" Text="{TemplateBinding DisplayValue}"
TextAlignment="{TemplateBinding HorizontalContentAlignment}" TextAlignment="{TemplateBinding HorizontalContentAlignment}"
@ -457,12 +458,13 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ActiveStates"> <VisualStateGroup x:Name="ActiveStates">
<VisualState x:Name="Active"/> <VisualState x:Name="Active">
<VisualState x:Name="Normal">
<VisualState.Setters> <VisualState.Setters>
<Setter Target="normalOutput.FontWeight" Value="Light"/> <Setter Target="normalOutput.IsTextSelectionEnabled" Value="True"/>
<Setter Target="normalOutput.FontWeight" Value="SemiBold"/>
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
<VisualState x:Name="Normal"/>
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
<ScrollViewer x:Name="textContainer" <ScrollViewer x:Name="textContainer"
@ -476,7 +478,7 @@
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
FontSize="{TemplateBinding FontSize}" FontSize="{TemplateBinding FontSize}"
FontWeight="SemiBold" FontWeight="Light"
AutomationProperties.AccessibilityView="Raw" AutomationProperties.AccessibilityView="Raw"
Text="{TemplateBinding DisplayValue}" Text="{TemplateBinding DisplayValue}"
TextAlignment="{TemplateBinding HorizontalContentAlignment}" TextAlignment="{TemplateBinding HorizontalContentAlignment}"
@ -544,12 +546,13 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ActiveStates"> <VisualStateGroup x:Name="ActiveStates">
<VisualState x:Name="Active"/> <VisualState x:Name="Active">
<VisualState x:Name="Normal">
<VisualState.Setters> <VisualState.Setters>
<Setter Target="normalOutput.FontWeight" Value="Light"/> <Setter Target="normalOutput.FontWeight" Value="SemiBold"/>
<Setter Target="normalOutput.IsTextSelectionEnabled" Value="True"/>
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
<VisualState x:Name="Normal"/>
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
<ScrollViewer x:Name="textContainer" <ScrollViewer x:Name="textContainer"
@ -563,7 +566,7 @@
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{TemplateBinding Foreground}" Foreground="{TemplateBinding Foreground}"
FontSize="{TemplateBinding FontSize}" FontSize="{TemplateBinding FontSize}"
FontWeight="SemiBold" FontWeight="Light"
AutomationProperties.AccessibilityView="Raw" AutomationProperties.AccessibilityView="Raw"
Text="{TemplateBinding DisplayValue}" Text="{TemplateBinding DisplayValue}"
TextAlignment="{TemplateBinding HorizontalContentAlignment}" TextAlignment="{TemplateBinding HorizontalContentAlignment}"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 384 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 484 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

After

Width:  |  Height:  |  Size: 728 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 234 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 B

After

Width:  |  Height:  |  Size: 441 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 470 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 511 B

Before After
Before After

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