diff --git a/README.md b/README.md index b56f3ef3..386e871d 100644 --- a/README.md +++ b/README.md @@ -64,12 +64,7 @@ for your use. The mock data will be clearly identifiable as it references planet and remains static regardless of selected inputs. ## Reporting Security Issues -Security issues and bugs should be reported privately, via email, to the -Microsoft Security Response Center (MSRC) at <[secure@microsoft.com](mailto:secure@microsoft.com)>. -You should receive a response within 24 hours. If for some reason you do not, please follow up via -email to ensure we received your original message. Further information, including the -[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in the -[Security TechCenter](https://technet.microsoft.com/en-us/security/default). +Please refer to [SECURITY.md](./SECURITY.md). ## License Copyright (c) Microsoft Corporation. All rights reserved. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..1b724719 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,48 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all +source code repositories managed through our GitHub organizations, which include +[Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), +[DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), +[Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets +Microsoft's [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) +of a security vulnerability, please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** Instead, please +report them to the Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com). +If possible, encrypt your message with our PGP key; please download it from the +[Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via +email to ensure we received your original message. Additional information can be found at +[microsoft.com/msrc](https://www.microsoft.com/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better +understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of +[Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). + + diff --git a/build/pipelines/azure-pipelines.ci.yaml b/build/pipelines/azure-pipelines.ci.yaml index d980165e..3f7faf16 100644 --- a/build/pipelines/azure-pipelines.ci.yaml +++ b/build/pipelines/azure-pipelines.ci.yaml @@ -7,9 +7,11 @@ trigger: - master - servicing/* +- feature/* pr: - master - servicing/* +- feature/* name: 0.$(Date:yyMM).$(DayOfMonth)$(Rev:rr).0 @@ -21,7 +23,6 @@ jobs: - template: ./templates/build-app-public.yaml parameters: platform: x86 - condition: not(eq(variables['Build.Reason'], 'PullRequest')) - template: ./templates/build-app-public.yaml parameters: @@ -41,15 +42,9 @@ jobs: - template: ./templates/run-unit-tests.yaml parameters: platform: x64 - reimageServiceConnection: essential-experiences-interactive-reimage - reimageSubscriptionId: a8f5eb47-e59c-44b4-8e42-e70811a047b5 - reimageResourceGroup: EETestPublic - template: ./templates/run-unit-tests.yaml parameters: platform: x86 - reimageServiceConnection: essential-experiences-interactive-reimage - reimageSubscriptionId: a8f5eb47-e59c-44b4-8e42-e70811a047b5 - reimageResourceGroup: EETestPublic - template: ./templates/package-appxbundle.yaml diff --git a/build/pipelines/azure-pipelines.loc.yaml b/build/pipelines/azure-pipelines.loc.yaml index 7c5ef246..287188be 100644 --- a/build/pipelines/azure-pipelines.loc.yaml +++ b/build/pipelines/azure-pipelines.loc.yaml @@ -15,11 +15,10 @@ name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) jobs: - job: Localize pool: - vmImage: vs2017-win2016 + vmImage: windows-2019 variables: skipComponentGovernanceDetection: true steps: - - task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@1 displayName: Send resources to Touchdown Build inputs: diff --git a/build/pipelines/azure-pipelines.release.yaml b/build/pipelines/azure-pipelines.release.yaml index c26df788..33e10c63 100644 --- a/build/pipelines/azure-pipelines.release.yaml +++ b/build/pipelines/azure-pipelines.release.yaml @@ -9,8 +9,8 @@ pr: none variables: versionMajor: 10 - versionMinor: 1907 - versionBuild: $[counter('10.1907.*', 0)] + versionMinor: 1910 + versionBuild: $[counter('10.1910.*', 0)] versionPatch: 0 name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)' @@ -48,16 +48,10 @@ jobs: - template: ./templates/run-unit-tests.yaml parameters: platform: x64 - reimageServiceConnection: macool-sandbox-interactiveDesktopRS5 - reimageSubscriptionId: 012a8008-c00f-45b3-9828-41ebba30141d - reimageResourceGroup: interactiveDesktopRS5 - template: ./templates/run-unit-tests.yaml parameters: platform: x86 - reimageServiceConnection: macool-sandbox-interactiveDesktopRS5 - reimageSubscriptionId: 012a8008-c00f-45b3-9828-41ebba30141d - reimageResourceGroup: interactiveDesktopRS5 - template: ./templates/package-appxbundle.yaml diff --git a/build/pipelines/templates/build-app-internal.yaml b/build/pipelines/templates/build-app-internal.yaml index 9dc0d421..51eb1d28 100644 --- a/build/pipelines/templates/build-app-internal.yaml +++ b/build/pipelines/templates/build-app-internal.yaml @@ -21,7 +21,7 @@ jobs: steps: - checkout: self clean: true - + - task: UniversalPackages@0 displayName: Download internals package inputs: @@ -29,7 +29,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.11 + vstsPackageVersion: 0.0.31 - template: ./build-single-architecture.yaml parameters: @@ -64,4 +64,4 @@ jobs: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: Detect open source components inputs: - sourceScanPath: $(Agent.BuildDirectory) \ No newline at end of file + sourceScanPath: $(Agent.BuildDirectory) diff --git a/build/pipelines/templates/prepare-release-internalonly.yaml b/build/pipelines/templates/prepare-release-internalonly.yaml index a6b43a1b..9c7a45ea 100644 --- a/build/pipelines/templates/prepare-release-internalonly.yaml +++ b/build/pipelines/templates/prepare-release-internalonly.yaml @@ -19,6 +19,12 @@ jobs: clean: outputs variables: skipComponentGovernanceDetection: true + SBMediaRootPath: '$(TEMP)\SBMedia' + SBPackagePath: '$(Build.ArtifactStagingDirectory)\storeBrokerPayload' + SBLogPath: '$(SBPackagePath)\StoreBroker.log' + FlightId: '161f0975-cb5f-475b-8ef6-26383c37621f' + AppId: '9WZDNCRFHVN5' + ProductId: '00009007199266248474' steps: - checkout: self clean: true @@ -91,61 +97,74 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.11 + vstsPackageVersion: 0.0.22 - - task: PkgESStoreBrokerPackage@10 - displayName: Create StoreBroker Packages - env: - XES_SERIALPOSTBUILDREADY: True + - powershell: | + # Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone. + $enUSPdpFilePath = "$(Build.SourcesDirectory)\PDP\en-US\PDP.xml" + + # This is going to save the release value from the PDP file to $(SBMediaReleaseVersion) + # which you can then refer to in the UniversalPackages task. + $release = ([xml](Get-Content $enUSPdpFilePath)).ProductDescription.Release.Trim() + Write-Host "##vso[task.setvariable variable=SBMediaReleaseVersion;]$release" + displayName: Determine the PDP Media release version from the en-us PDP file + + - task: UniversalPackages@0 + displayName: Download PDP media (screenshots, trailers) universal package inputs: - addToFlight: false - configPath: tools/Build/StoreBroker/SBCalculatorConfig.json - PDPRootPath: $(Build.SourcesDirectory)\PDP - imagesRootPath: $(Build.SourcesDirectory)\PDPMediaRoot - appxPath: $(Build.ArtifactStagingDirectory)\appxBundleSigned\Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle - useArtifactServiceForMedia: true - outPath: $(Build.ArtifactStagingDirectory)\StoreBrokerPayload - paToken: $(System.AccessToken) - logRootPath: $(Build.ArtifactStagingDirectory)/StoreBrokerLogs + command: download + downloadDirectory: $(SBMediaRootPath)/$(SBMediaReleaseVersion) + vstsFeed: WindowsInboxApps + vstsFeedPackage: calculator-pdp-media + vstsPackageVersion: $(SBMediaReleaseVersion) + + - task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@2 + displayName: Create StoreBroker Payload + inputs: + serviceEndpoint: StoreBrokerProxy + sbConfigPath: Tools/Build/StoreBroker/SBCalculatorConfig.json + sourceFolder: $(Build.ArtifactStagingDirectory)/appxBundleSigned + contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle + pdpPath: '$(Build.SourcesDirectory)\PDP' + pdpInclude: PDP.xml + pdpMediaPath: '$(SBMediaRootPath)' + outSBPackagePath: '$(SBPackagePath)' + outSBName: SBCalculator - task: PublishBuildArtifacts@1 - displayName: Publish StoreBrokerPayload artifact + displayName: Publish StoreBroker Payload artifact inputs: + pathtoPublish: '$(SBPackagePath)' artifactName: storeBrokerPayload - pathToPublish: $(Build.ArtifactStagingDirectory)/StoreBrokerPayload - - task: PkgESStoreBrokerFlight@10 + - task: MS-RDX-MRO.windows-store-publish-dev.flight-task.store-flight@2 + displayName: 'Flight StoreBroker Payload to team ring' name: StoreBrokerFlight - displayName: Flight package with StoreBroker - env: - XES_SERIALPOSTBUILDREADY: True inputs: - packageToFlight: Custom - appId: 9WZDNCRFHVN5 - flightId: 161f0975-cb5f-475b-8ef6-26383c37621f - submissionDataPath: $(Build.ArtifactStagingDirectory)/StoreBrokerPayload/SBCalculator.json - packagePath: $(Build.ArtifactStagingDirectory)/StoreBrokerPayload/SBCalculator.zip - updatePackageAction: AddPackages - logRootPath: $(Build.ArtifactStagingDirectory)/StoreBrokerLogs - - - task: PublishBuildArtifacts@1 - displayName: Publish StoreBrokerLogs artifact - inputs: - artifactName: storeBrokerLogs - pathToPublish: $(Build.ArtifactStagingDirectory)/StoreBrokerLogs + serviceEndpoint: StoreBrokerProxy + appId: '$(AppId)' + flightId: '$(FlightId)' + inputMethod: JsonAndZip + jsonPath: '$(SBPackagePath)\SBCalculator.json' + zipPath: '$(SBPackagePath)\SBCalculator.zip' + force: true + skipPolling: true + targetPublishMode: Immediate + logPath: '$(SBLogPath)' - task: PkgESStoreBrokerAeroUpload@10 displayName: Upload to Aero flighting dashboard env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) inputs: - productId: 00009007199266248474 - flightId: 161f0975-cb5f-475b-8ef6-26383c37621f - submissionId: $(StoreBrokerFlight.WS_SubmissionId) - submissionDataPath: $(Build.ArtifactStagingDirectory)/StoreBrokerPayload/SBCalculator.json - packagePath: $(Build.ArtifactStagingDirectory)/StoreBrokerPayload/SBCalculator.zip + ProductId: '$(ProductId)' + FlightId: '$(FlightId)' + SubmissionId: '$(StoreBrokerFlight.WS_SubmissionId)' + SubmissionDataPath: '$(SBPackagePath)\SBCalculator.json' + PackagePath: '$(SBPackagePath)\SBCalculator.zip' + AeroEnvironment: Production - task: PkgESLateTasks@10 displayName: Run PackageES LateTasks env: - XES_DISABLEPROV: true \ No newline at end of file + XES_DISABLEPROV: true diff --git a/build/pipelines/templates/run-unit-tests.yaml b/build/pipelines/templates/run-unit-tests.yaml index 2a000118..56f60969 100644 --- a/build/pipelines/templates/run-unit-tests.yaml +++ b/build/pipelines/templates/run-unit-tests.yaml @@ -1,29 +1,20 @@ -# This template contains jobs to run unit tests on the interactive test agents. +# This template contains jobs to run unit tests. parameters: platform: '' - reimageServiceConnection: '' - reimageSubscriptionId: '' - reimageResourceGroup: '' + runsettingsFileName: '' jobs: - job: UnitTests${{ parameters.platform }} displayName: UnitTests ${{ parameters.platform }} dependsOn: Build${{ parameters.platform }} + condition: succeeded() pool: - name: Essential Experiences Interactive - workspace: - clean: outputs + vmImage: windows-2019 variables: skipComponentGovernanceDetection: true steps: - checkout: none - - - powershell: Write-Host "##vso[task.setvariable variable=agentInstanceId;isOutput=true]$($env:AgentName -replace '\D+' -as [int])" - name: LogAgentStep - displayName: Log this agent's instance for later cleanup - env: - AgentName: $(Agent.Name) - task: DownloadBuildArtifacts@0 displayName: Download CalculatorUnitTests @@ -41,19 +32,4 @@ jobs: displayName: Run CalculatorUnitTests inputs: testAssemblyVer2: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.appx - otherConsoleOptions: /Platform:${{ parameters.platform }} - -- job: CleanUpUnitTests${{ parameters.platform }} - dependsOn: UnitTests${{ parameters.platform }} - condition: and(always(), ne(dependencies.UnitTests${{ parameters.platform }}.Outputs['LogAgentStep.agentInstanceId'], '')) - pool: server - variables: - agentInstanceId: $[ dependencies.UnitTests${{ parameters.platform }}.outputs['LogAgentStep.agentInstanceId'] ] - steps: - - task: InvokeRESTAPI@1 - displayName: Reimage test machine - inputs: - connectionType: connectedServiceNameARM - azureServiceConnection: ${{ parameters.reimageServiceConnection }} - urlSuffix: subscriptions/${{ parameters.reimageSubscriptionId }}/resourceGroups/${{ parameters.reimageResourceGroup }}/providers/Microsoft.Compute/virtualMachineScaleSets/essential/reimage?api-version=2018-10-01 - body: '{ "instanceIds": ["$(agentInstanceId)"] }' \ No newline at end of file + otherConsoleOptions: /Platform:${{ parameters.platform }} \ No newline at end of file diff --git a/src/CalcManager/CEngine/CalcInput.cpp b/src/CalcManager/CEngine/CalcInput.cpp index 600f9002..5bbc1408 100644 --- a/src/CalcManager/CEngine/CalcInput.cpp +++ b/src/CalcManager/CEngine/CalcInput.cpp @@ -179,7 +179,7 @@ bool CalcInput::TryAddDecimalPt() if (m_base.IsEmpty()) { - m_base.value += L"0"; // Add a leading zero + m_base.value += L'0'; // Add a leading zero } m_decPtIndex = m_base.value.size(); @@ -231,6 +231,10 @@ void CalcInput::Backspace() if (!m_base.IsEmpty()) { m_base.value.pop_back(); + if (m_base.value == L"0") + { + m_base.value.pop_back(); + } } if (m_base.value.size() <= m_decPtIndex) @@ -261,37 +265,55 @@ void CalcInput::SetDecimalSymbol(wchar_t decSymbol) } } +bool CalcInput::IsEmpty() +{ + return m_base.IsEmpty() && !m_hasExponent && m_exponent.IsEmpty() && !m_hasDecimal; +} + wstring CalcInput::ToString(uint32_t radix) { // In theory both the base and exponent could be C_NUM_MAX_DIGITS long. - wstringstream resStream; - if ((m_base.value.size() > MAX_STRLEN) || (m_hasExponent && m_exponent.value.size() > MAX_STRLEN)) { return wstring(); } + wstring result; + if (m_base.IsNegative()) { - resStream << L'-'; + result = L'-'; } - resStream << (m_base.IsEmpty() ? L"0" : m_base.value); + if (m_base.IsEmpty()) + { + result += L'0'; + } + else + { + result += m_base.value; + } if (m_hasExponent) { // Add a decimal point if it is not already there if (!m_hasDecimal) { - resStream << m_decSymbol; + result += m_decSymbol; } - resStream << ((radix == 10) ? L'e' : L'^'); - resStream << (m_exponent.IsNegative() ? L'-' : L'+'); - resStream << (m_exponent.IsEmpty() ? L"0" : m_exponent.value); - } + result += ((radix == 10) ? L'e' : L'^'); + result += (m_exponent.IsNegative() ? L'-' : L'+'); - auto result = resStream.str(); + if (m_exponent.IsEmpty()) + { + result += L'0'; + } + else + { + result += m_exponent.value; + } + } // Base and Exp can each be up to C_NUM_MAX_DIGITS in length, plus 4 characters for sign, dec, exp, and expSign. if (result.size() > C_NUM_MAX_DIGITS * 2 + 4) diff --git a/src/CalcManager/CEngine/CalcUtils.cpp b/src/CalcManager/CEngine/CalcUtils.cpp index 57510dcc..8807627f 100644 --- a/src/CalcManager/CEngine/CalcUtils.cpp +++ b/src/CalcManager/CEngine/CalcUtils.cpp @@ -11,14 +11,14 @@ bool IsOpInRange(OpCode op, uint32_t x, uint32_t y) bool IsBinOpCode(OpCode opCode) { - return IsOpInRange(opCode, IDC_AND, IDC_PWR); + return IsOpInRange(opCode, IDC_AND, IDC_PWR) || IsOpInRange(opCode, IDC_BINARYEXTENDEDFIRST, IDC_BINARYEXTENDEDLAST); } // WARNING: IDC_SIGN is a special unary op but still this doesn't catch this. Caller has to be aware // of it and catch it themselves or not needing this bool IsUnaryOpCode(OpCode opCode) { - return IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST); + return (IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST) || IsOpInRange(opCode, IDC_UNARYEXTENDEDFIRST, IDC_UNARYEXTENDEDLAST)); } bool IsDigitOpCode(OpCode opCode) diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp index 37add769..d3a32ebb 100644 --- a/src/CalcManager/CEngine/History.cpp +++ b/src/CalcManager/CEngine/History.cpp @@ -3,7 +3,6 @@ #include "Header Files/CalcEngine.h" #include "Command.h" -#include "CalculatorVector.h" #include "ExpressionCommand.h" constexpr int ASCII_0 = 48; @@ -13,14 +12,19 @@ using namespace CalcEngine; namespace { - void IFT(ResultCode hr) + template + static void Truncate(vector& v, unsigned int index) { - if (FAILED(hr)) + if (index >= v.size()) { - throw hr; + throw E_BOUNDS; } + + auto startIter = v.begin() + index; + v.erase(startIter, v.end()); } } + void CHistoryCollector::ReinitHistory() { m_lastOpStartIndex = -1; @@ -29,11 +33,11 @@ void CHistoryCollector::ReinitHistory() m_bLastOpndBrace = false; if (m_spTokens != nullptr) { - m_spTokens->Clear(); + m_spTokens->clear(); } if (m_spCommands != nullptr) { - m_spCommands->Clear(); + m_spCommands->clear(); } } @@ -55,13 +59,13 @@ CHistoryCollector::~CHistoryCollector() if (m_spTokens != nullptr) { - m_spTokens->Clear(); + m_spTokens->clear(); } } void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& rat, bool fRepetition) { - std::shared_ptr> commands = std::make_shared>(); + std::shared_ptr> commands = std::make_shared>(); // Check for negate bool fNegative = (numStr[0] == L'-'); bool fSciFmt = false; @@ -71,7 +75,7 @@ void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& ra { if (numStr[i] == m_decimalSymbol) { - IFT(commands->Append(IDC_PNT)); + commands->push_back(IDC_PNT); if (!fSciFmt) { fDecimal = true; @@ -79,12 +83,12 @@ void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& ra } else if (numStr[i] == L'e') { - IFT(commands->Append(IDC_EXP)); + commands->push_back(IDC_EXP); fSciFmt = true; } else if (numStr[i] == L'-') { - IFT(commands->Append(IDC_SIGN)); + commands->push_back(IDC_SIGN); } else if (numStr[i] == L'+') { @@ -95,7 +99,7 @@ void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& ra { int num = static_cast(numStr[i]) - ASCII_0; num += IDC_0; - IFT(commands->Append(num)); + commands->push_back(num); } } @@ -120,12 +124,12 @@ void CHistoryCollector::RemoveLastOpndFromHistory() // This will not restore the m_lastBinOpStartIndex, as it isn't possible to remove that also later } -void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool fNoRepetition) +void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool isIntegerMode, bool fNoRepetition) { int iCommandEnd = AddCommand(std::make_shared(nOpCode)); m_lastBinOpStartIndex = IchAddSzToEquationSz(L" ", -1); - IchAddSzToEquationSz(CCalcEngine::OpCodeToString(nOpCode), iCommandEnd); + IchAddSzToEquationSz(CCalcEngine::OpCodeToBinaryString(nOpCode, isIntegerMode), iCommandEnd); IchAddSzToEquationSz(L" ", -1); if (fNoRepetition) @@ -138,14 +142,14 @@ 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 *) // 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) ^) -void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher) +void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode) { TruncateEquationSzFromIch(m_lastBinOpStartIndex); if (fPrecInvToHigher) { EnclosePrecInversionBrackets(); } - AddBinOpToHistory(nOpCode); + AddBinOpToHistory(nOpCode, isIntgerMode); } void CHistoryCollector::PushLastOpndStart(int ichOpndStart) @@ -266,6 +270,30 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a command = fInv ? static_cast(CalculationManager::Command::CommandATANH) : IDC_TANH; spExpressionCommand = std::make_shared(command); break; + case IDC_SEC: + command = fInv ? static_cast(CalculationManager::Command::CommandASEC) : IDC_SEC; + spExpressionCommand = std::make_shared(static_cast(angleOpCode), command); + break; + case IDC_CSC: + command = fInv ? static_cast(CalculationManager::Command::CommandACSC) : IDC_CSC; + spExpressionCommand = std::make_shared(static_cast(angleOpCode), command); + break; + case IDC_COT: + command = fInv ? static_cast(CalculationManager::Command::CommandACOT) : IDC_COT; + spExpressionCommand = std::make_shared(static_cast(angleOpCode), command); + break; + case IDC_SECH: + command = fInv ? static_cast(CalculationManager::Command::CommandASECH) : IDC_SECH; + spExpressionCommand = std::make_shared(command); + break; + case IDC_CSCH: + command = fInv ? static_cast(CalculationManager::Command::CommandACSCH) : IDC_CSCH; + spExpressionCommand = std::make_shared(command); + break; + case IDC_COTH: + command = fInv ? static_cast(CalculationManager::Command::CommandACOTH) : IDC_COTH; + spExpressionCommand = std::make_shared(command); + break; case IDC_LN: command = fInv ? static_cast(CalculationManager::Command::CommandPOWE) : IDC_LN; spExpressionCommand = std::make_shared(command); @@ -301,12 +329,6 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a // history of equations void CHistoryCollector::CompleteHistoryLine(wstring_view numStr) { - if (nullptr != m_pCalcDisplay) - { - m_pCalcDisplay->SetExpressionDisplay( - std::make_shared>>(), std::make_shared>>()); - } - if (nullptr != m_pHistoryDisplay) { unsigned int addedItemIndex = m_pHistoryDisplay->AddToHistory(m_spTokens, m_spCommands, numStr); @@ -319,6 +341,16 @@ void CHistoryCollector::CompleteHistoryLine(wstring_view numStr) ReinitHistory(); } +void CHistoryCollector::CompleteEquation(std::wstring_view numStr) +{ + // Add only '=' token and not add EQU command, because + // EQU command breaks loading from history (it duplicate history entries). + IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_EQU), -1); + + SetExpressionDisplay(); + CompleteHistoryLine(numStr); +} + void CHistoryCollector::ClearHistoryLine(wstring_view errStr) { if (errStr.empty()) // in case of error let the display stay as it is @@ -326,7 +358,7 @@ void CHistoryCollector::ClearHistoryLine(wstring_view errStr) if (nullptr != m_pCalcDisplay) { m_pCalcDisplay->SetExpressionDisplay( - std::make_shared>>(), std::make_shared>>()); + std::make_shared>>(), std::make_shared>>()); } m_iCurLineHistStart = -1; // It will get recomputed at the first Opnd ReinitHistory(); @@ -339,26 +371,17 @@ int CHistoryCollector::IchAddSzToEquationSz(wstring_view str, int icommandIndex) { if (m_spTokens == nullptr) { - m_spTokens = std::make_shared>>(); + m_spTokens = std::make_shared>>(); } - if (FAILED(m_spTokens->Append(std::make_pair(wstring(str), icommandIndex)))) - { - throw(CALC_E_OUTOFMEMORY); - } - - unsigned int nTokens; - m_spTokens->GetSize(&nTokens); - return nTokens - 1; + m_spTokens->push_back(std::pair(wstring(str), icommandIndex)); + return static_cast(m_spTokens->size() - 1); } // Inserts a given string into the global m_pszEquation at the given index ich taking care of reallocations etc. void CHistoryCollector::InsertSzInEquationSz(wstring_view str, int icommandIndex, int ich) { - if (FAILED(m_spTokens->InsertAt(ich, std::make_pair(wstring(str), icommandIndex)))) - { - throw(CALC_E_OUTOFMEMORY); - } + m_spTokens->emplace(m_spTokens->begin() + ich, wstring(str), icommandIndex); } // Chops off the current equation string from the given index @@ -366,25 +389,23 @@ void CHistoryCollector::TruncateEquationSzFromIch(int ich) { // Truncate commands int minIdx = -1; - unsigned int nTokens = 0; - std::pair currentPair; - m_spTokens->GetSize(&nTokens); + unsigned int nTokens = static_cast(m_spTokens->size()); for (unsigned int i = ich; i < nTokens; i++) { - IFT(m_spTokens->GetAt(i, ¤tPair)); + const auto& currentPair = (*m_spTokens)[i]; int curTokenId = currentPair.second; if (curTokenId != -1) { if ((minIdx != -1) || (curTokenId < minIdx)) { minIdx = curTokenId; - IFT(m_spCommands->Truncate(minIdx)); + Truncate(*m_spCommands, minIdx); } } } - IFT(m_spTokens->Truncate(ich)); + Truncate(*m_spTokens, ich); } // Adds the m_pszEquation into the running history text @@ -400,17 +421,11 @@ int CHistoryCollector::AddCommand(_In_ const std::shared_ptr { if (m_spCommands == nullptr) { - m_spCommands = std::make_shared>>(); + m_spCommands = std::make_shared>>(); } - if (FAILED(m_spCommands->Append(spCommand))) - { - throw(CALC_E_OUTOFMEMORY); - } - - unsigned int nCommands = 0; - m_spCommands->GetSize(&nCommands); - return nCommands - 1; + m_spCommands->push_back(spCommand); + return static_cast(m_spCommands->size() - 1); } // To Update the operands in the Expression according to the current Radix @@ -421,30 +436,25 @@ void CHistoryCollector::UpdateHistoryExpression(uint32_t radix, int32_t precisio return; } - unsigned int size; - IFT(m_spTokens->GetSize(&size)); - - for (unsigned int i = 0; i < size; ++i) + for (auto& token : *m_spTokens) { - std::pair token; - IFT(m_spTokens->GetAt(i, &token)); int commandPosition = token.second; if (commandPosition != -1) { - std::shared_ptr expCommand; - IFT(m_spCommands->GetAt(commandPosition, &expCommand)); + const std::shared_ptr& expCommand = m_spCommands->at(commandPosition); + if (expCommand != nullptr && CalculationManager::CommandType::OperandCommand == expCommand->GetCommandType()) { - std::shared_ptr opndCommand = std::static_pointer_cast(expCommand); + const std::shared_ptr& opndCommand = std::static_pointer_cast(expCommand); if (opndCommand != nullptr) { token.first = opndCommand->GetString(radix, precision); - IFT(m_spTokens->SetAt(i, token)); opndCommand->SetCommands(GetOperandCommandsFromString(token.first)); } } } } + SetExpressionDisplay(); } @@ -454,9 +464,9 @@ void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol) } // Update the commands corresponding to the passed string Number -std::shared_ptr> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) +std::shared_ptr> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) { - std::shared_ptr> commands = std::make_shared>(); + std::shared_ptr> commands = std::make_shared>(); // Check for negate bool fNegative = (numStr[0] == L'-'); @@ -464,15 +474,15 @@ std::shared_ptr> CHistoryCollector::GetOperandCommandsFrom { if (numStr[i] == m_decimalSymbol) { - IFT(commands->Append(IDC_PNT)); + commands->push_back(IDC_PNT); } else if (numStr[i] == L'e') { - IFT(commands->Append(IDC_EXP)); + commands->push_back(IDC_EXP); } else if (numStr[i] == L'-') { - IFT(commands->Append(IDC_SIGN)); + commands->push_back(IDC_SIGN); } else if (numStr[i] == L'+') { @@ -483,14 +493,14 @@ std::shared_ptr> CHistoryCollector::GetOperandCommandsFrom { int num = static_cast(numStr[i]) - ASCII_0; num += IDC_0; - IFT(commands->Append(num)); + commands->push_back(num); } } // If the number is negative, append a sign command at the end. if (fNegative) { - IFT(commands->Append(IDC_SIGN)); + commands->push_back(IDC_SIGN); } return commands; } diff --git a/src/CalcManager/CEngine/calc.cpp b/src/CalcManager/CEngine/calc.cpp index c71d2927..c5775379 100644 --- a/src/CalcManager/CEngine/calc.cpp +++ b/src/CalcManager/CEngine/calc.cpp @@ -24,17 +24,16 @@ static constexpr wstring_view DEFAULT_NUMBER_STR = L"0"; // Read strings for keys, errors, trig types, etc. // These will be copied from the resources to local memory. -unordered_map CCalcEngine::s_engineStrings; +unordered_map CCalcEngine::s_engineStrings; void CCalcEngine::LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider) { for (const auto& sid : g_sids) { - auto locKey = wstring{ sid }; - auto locString = resourceProvider.GetCEngineString(locKey); + auto locString = resourceProvider.GetCEngineString(sid); if (!locString.empty()) { - s_engineStrings[locKey] = locString; + s_engineStrings[sid] = locString; } } } diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp index 20790f88..f7509ab3 100644 --- a/src/CalcManager/CEngine/scicomm.cpp +++ b/src/CalcManager/CEngine/scicomm.cpp @@ -16,6 +16,7 @@ #include #include "Header Files/CalcEngine.h" #include "Header Files/CalcUtils.h" +#include "NumberFormattingUtils.h" using namespace std; using namespace CalcEngine; @@ -28,8 +29,13 @@ namespace // 0 is returned. Higher the number, higher the precedence of the operator. int NPrecedenceOfOp(int nopCode) { - static uint8_t rgbPrec[] = { 0, 0, IDC_OR, 0, IDC_XOR, 0, IDC_AND, 1, IDC_ADD, 2, IDC_SUB, 2, IDC_RSHF, - 3, IDC_LSHF, 3, IDC_MOD, 3, IDC_DIV, 3, IDC_MUL, 3, IDC_PWR, 4, IDC_ROOT, 4 }; + static uint16_t rgbPrec[] = { + 0,0, IDC_OR,0, IDC_XOR,0, + IDC_AND,1, IDC_NAND,1, IDC_NOR,1, + IDC_ADD,2, IDC_SUB,2, + IDC_RSHF,3, IDC_LSHF,3, IDC_RSHFL,3, + IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, + IDC_PWR,4, IDC_ROOT,4, IDC_LOGBASEX,4 }; unsigned int iPrec; iPrec = 0; @@ -76,6 +82,15 @@ void CCalcEngine::ClearTemporaryValues() m_bError = false; } +void CCalcEngine::ClearDisplay() +{ + if (nullptr != m_pCalcDisplay) + { + m_pCalcDisplay->SetExpressionDisplay( + make_shared>>(), make_shared>>()); + } +} + void CCalcEngine::ProcessCommand(OpCode wParam) { if (wParam == IDC_SET_RESULT) @@ -103,6 +118,12 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_nTempCom = (int)wParam; } + // Clear expression shown after = sign, when user do any action. + if (!m_bNoPrevEqu) + { + ClearDisplay(); + } + if (m_bError) { if (wParam == IDC_CLEAR) @@ -124,9 +145,18 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) // Toggle Record/Display mode if appropriate. if (m_bRecord) { - if (IsOpInRange(wParam, IDC_AND, IDC_MMINUS) || IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || IsOpInRange(wParam, IDM_HEX, IDM_BIN) - || IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || IsOpInRange(wParam, IDM_DEG, IDM_GRAD) - || IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63) || (IDC_INV == wParam) || (IDC_SIGN == wParam && 10 != m_radix)) + if (IsBinOpCode(wParam) || + IsUnaryOpCode(wParam) || + IsOpInRange(wParam, IDC_FE, IDC_MMINUS) || + IsOpInRange(wParam, IDC_OPENP, IDC_CLOSEP) || + IsOpInRange(wParam, IDM_HEX, IDM_BIN) || + IsOpInRange(wParam, IDM_QWORD, IDM_BYTE) || + IsOpInRange(wParam, IDM_DEG, IDM_GRAD) || + IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITEND) || + (IDC_INV == wParam) || + (IDC_SIGN == wParam && 10 != m_radix) || + (IDC_RAND == wParam) || + (IDC_EULER == wParam)) { m_bRecord = false; m_currentVal = m_input.ToRational(m_radix, m_precision); @@ -193,7 +223,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_nPrevOpCode = 0; // Once the precedence inversion has put additional brackets, its no longer required } } - m_HistoryCollector.ChangeLastBinOp(m_nOpCode, fPrecInvToHigher); + m_HistoryCollector.ChangeLastBinOp(m_nOpCode, fPrecInvToHigher, m_fIntegerMode); DisplayAnnounceBinaryOperator(); return; } @@ -270,10 +300,9 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) } DisplayAnnounceBinaryOperator(); - m_lastVal = m_currentVal; m_nOpCode = (int)wParam; - m_HistoryCollector.AddBinOpToHistory(m_nOpCode); + m_HistoryCollector.AddBinOpToHistory(m_nOpCode, m_fIntegerMode); m_bNoPrevEqu = m_bChangeOp = true; return; } @@ -303,7 +332,8 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_HistoryCollector.AddUnaryOpToHistory((int)wParam, m_bInv, m_angletype); } - if ((wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)) + if ((wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH) + || (wParam == IDC_SEC) || (wParam == IDC_CSC) || (wParam == IDC_COT) || (wParam == IDC_SECH) || (wParam == IDC_CSCH) || (wParam == IDC_COTH)) { if (IsCurrentTooBigForTrig()) { @@ -330,9 +360,13 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) /* reset the m_bInv flag and indicators if it is set and have been used */ - if (m_bInv - && ((wParam == IDC_CHOP) || (wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_LN) || (wParam == IDC_DMS) - || (wParam == IDC_DEGREES) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH))) + if (m_bInv && + ((wParam == IDC_CHOP) || (wParam == IDC_SIN) || (wParam == IDC_COS) || + (wParam == IDC_TAN) || (wParam == IDC_LN) || (wParam == IDC_DMS) || + (wParam == IDC_DEGREES) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || + (wParam == IDC_TANH) || (wParam == IDC_SEC) || (wParam == IDC_CSC) || + (wParam == IDC_COT) || (wParam == IDC_SECH) || (wParam == IDC_CSCH) || + (wParam == IDC_COTH))) { m_bInv = false; } @@ -341,10 +375,10 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) } // Tiny binary edit windows clicked. Toggle that bit and update display - if (IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITSTART + 63)) + if (IsOpInRange(wParam, IDC_BINEDITSTART, IDC_BINEDITEND)) { // Same reasoning as for unary operators. We need to seed it previous number - if (m_nLastCom >= IDC_AND && m_nLastCom <= IDC_PWR) + if (IsBinOpCode(m_nLastCom)) { m_currentVal = m_lastVal; } @@ -377,14 +411,14 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) m_precedenceOpCount = m_nTempCom = m_nLastCom = m_nOpCode = 0; m_nPrevOpCode = 0; m_bNoPrevEqu = true; + m_carryBit = 0; /* clear the parenthesis status box indicator, this will not be cleared for CENTR */ if (nullptr != m_pCalcDisplay) { m_pCalcDisplay->SetParenthesisNumber(0); - m_pCalcDisplay->SetExpressionDisplay( - make_shared>>(), make_shared>>()); + ClearDisplay(); } m_HistoryCollector.ClearHistoryLine(wstring()); @@ -474,12 +508,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) if (!m_bError) { wstring groupedString = GroupDigitsPerRadix(m_numberString, m_radix); - m_HistoryCollector.CompleteHistoryLine(groupedString); - if (nullptr != m_pCalcDisplay) - { - m_pCalcDisplay->SetExpressionDisplay( - make_shared>>(), make_shared>>()); - } + m_HistoryCollector.CompleteEquation(groupedString); } m_bChangeOp = false; @@ -700,7 +729,6 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) case IDC_MCLEAR: m_memoryValue = make_unique(wParam == IDC_STORE ? TruncateNumForIntMath(m_currentVal) : 0); break; - case IDC_PI: if (!m_fIntegerMode) { @@ -713,7 +741,43 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam) } HandleErrorCommand(wParam); break; + case IDC_RAND: + if (!m_fIntegerMode) + { + CheckAndAddLastBinOpToHistory(); // rand is like entering the number + wstringstream str; + str << fixed << setprecision(m_precision) << GenerateRandomNumber(); + + auto rat = StringToRat(false, str.str(), false, L"", m_radix, m_precision); + if (rat != nullptr) + { + m_currentVal = Rational{ rat }; + } + else + { + m_currentVal = Rational{ 0 }; + } + destroyrat(rat); + + DisplayNum(); + m_bInv = false; + break; + } + HandleErrorCommand(wParam); + break; + case IDC_EULER: + if (!m_fIntegerMode) + { + CheckAndAddLastBinOpToHistory(); // e is like entering the number + m_currentVal = Rational{ rat_exp }; + + DisplayNum(); + m_bInv = false; + break; + } + HandleErrorCommand(wParam); + break; case IDC_FE: // Toggle exponential notation display. m_nFE = NUMOBJ_FMT(!(int)m_nFE); @@ -761,7 +825,7 @@ void CCalcEngine::ResolveHighestPrecedenceOperation() { m_currentVal = m_holdVal; DisplayNum(); // to update the m_numberString - m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false); + m_HistoryCollector.AddBinOpToHistory(m_nOpCode, m_fIntegerMode, false); m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history } @@ -863,11 +927,14 @@ struct FunctionNameElement wstring gradString; wstring inverseGradString; // Will fall back to gradString if empty + wstring programmerModeString; + bool hasAngleStrings = ((!radString.empty()) || (!inverseRadString.empty()) || (!gradString.empty()) || (!inverseGradString.empty())); }; // Table for each unary operator -static const std::unordered_map unaryOperatorStringTable = { +static const std::unordered_map operatorStringTable = +{ { IDC_CHOP, { L"", SIDS_FRAC } }, { IDC_SIN, { SIDS_SIND, SIDS_ASIND, SIDS_SINR, SIDS_ASINR, SIDS_SING, SIDS_ASING } }, @@ -878,6 +945,14 @@ static const std::unordered_map unaryOperatorStringTab { IDC_COSH, { L"", SIDS_ACOSH } }, { IDC_TANH, { L"", SIDS_ATANH } }, + { IDC_SEC, { SIDS_SECD, SIDS_ASECD, SIDS_SECR, SIDS_ASECR, SIDS_SECG, SIDS_ASECG } }, + { IDC_CSC, { SIDS_CSCD, SIDS_ACSCD, SIDS_CSCR, SIDS_ACSCR, SIDS_CSCG, SIDS_ACSCG } }, + { IDC_COT, { SIDS_COTD, SIDS_ACOTD, SIDS_COTR, SIDS_ACOTR, SIDS_COTG, SIDS_ACOTG } }, + + { IDC_SECH, { SIDS_SECH, SIDS_ASECH } }, + { IDC_CSCH, { SIDS_CSCH, SIDS_ACSCH } }, + { IDC_COTH, { SIDS_COTH, SIDS_ACOTH } }, + { IDC_LN, { L"", SIDS_POWE } }, { IDC_SQR, { SIDS_SQR } }, { IDC_CUB, { SIDS_CUBE } }, @@ -885,7 +960,19 @@ static const std::unordered_map unaryOperatorStringTab { IDC_REC, { SIDS_RECIPROC } }, { IDC_DMS, { L"", SIDS_DEGREES } }, { IDC_SIGN, { SIDS_NEGATE } }, - { IDC_DEGREES, { SIDS_DEGREES } } + { IDC_DEGREES, { SIDS_DEGREES } }, + { IDC_POW2, { SIDS_TWOPOWX } }, + { IDC_LOGBASEX, { SIDS_LOGBASEX } }, + { IDC_ABS, { SIDS_ABS } }, + { IDC_CEIL, { SIDS_CEIL } }, + { IDC_FLOOR, { SIDS_FLOOR } }, + { IDC_NAND, { SIDS_NAND } }, + { IDC_NOR, { SIDS_NOR } }, + { IDC_RSHFL, { SIDS_RSH } }, + { IDC_RORC, { SIDS_ROR } }, + { IDC_ROLC, { SIDS_ROL } }, + { IDC_CUBEROOT, {SIDS_CUBEROOT} }, + { IDC_MOD, {SIDS_MOD, L"", L"", L"", L"", L"", SIDS_PROGRAMMER_MOD} }, }; wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype) @@ -893,7 +980,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE // Try to lookup the ID in the UFNE table wstring ids = L""; - if (auto pair = unaryOperatorStringTable.find(nOpCode); pair != unaryOperatorStringTable.end()) + if (auto pair = operatorStringTable.find(nOpCode); pair != operatorStringTable.end()) { const FunctionNameElement& element = pair->second; if (!element.hasAngleStrings || ANGLE_DEG == angletype) @@ -941,6 +1028,32 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE return OpCodeToString(nOpCode); } +wstring_view CCalcEngine::OpCodeToBinaryString(int nOpCode, bool isIntegerMode) +{ + // Try to lookup the ID in the UFNE table + wstring ids = L""; + + if (auto pair = operatorStringTable.find(nOpCode); pair != operatorStringTable.end()) + { + if (isIntegerMode && !pair->second.programmerModeString.empty()) + { + ids = pair->second.programmerModeString; + } + else + { + ids = pair->second.degreeString; + } + } + + if (!ids.empty()) + { + return GetString(ids); + } + + // If we didn't find an ID in the table, use the op code. + return OpCodeToString(nOpCode); +} + bool CCalcEngine::IsCurrentTooBigForTrig() { return m_currentVal >= m_maxTrigonometricNum; @@ -951,7 +1064,7 @@ int CCalcEngine::GetCurrentRadix() return m_radix; } -wstring CCalcEngine::GetCurrentResultForRadix(uint32_t radix, int32_t precision) +wstring CCalcEngine::GetCurrentResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix) { Rational rat = (m_bRecord ? m_input.ToRational(m_radix, m_precision) : m_currentVal); @@ -964,7 +1077,14 @@ wstring CCalcEngine::GetCurrentResultForRadix(uint32_t radix, int32_t precision) ChangeConstants(m_radix, m_precision); } - return GroupDigitsPerRadix(numberString, radix); + if (groupDigitsPerRadix) + { + return GroupDigitsPerRadix(numberString, radix); + } + else + { + return numberString; + } } wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix) @@ -1000,3 +1120,14 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix) return result; } + +double CCalcEngine::GenerateRandomNumber() +{ + if (m_randomGeneratorEngine == nullptr) + { + random_device rd; + m_randomGeneratorEngine = std::make_unique(rd()); + m_distr = std::make_unique>(0, 1); + } + return (*m_distr.get())(*m_randomGeneratorEngine.get()); +} diff --git a/src/CalcManager/CEngine/scidisp.cpp b/src/CalcManager/CEngine/scidisp.cpp index fed608d0..632969fd 100644 --- a/src/CalcManager/CEngine/scidisp.cpp +++ b/src/CalcManager/CEngine/scidisp.cpp @@ -215,10 +215,12 @@ int CCalcEngine::IsNumberInvalid(const wstring& numberString, int iMaxExp, int i \****************************************************************************/ vector CCalcEngine::DigitGroupingStringToGroupingVector(wstring_view groupingString) { - vector grouping{}; + vector grouping; uint32_t currentGroup = 0; wchar_t* next = nullptr; - for (const wchar_t* itr = groupingString.data(); *itr != L'\0'; ++itr) + const wchar_t* begin = groupingString.data(); + const wchar_t* end = begin + groupingString.length(); + for (auto itr = begin; itr != end; ++itr) { // Try to parse a grouping number from the string currentGroup = wcstoul(itr, &next, 10); @@ -232,7 +234,7 @@ vector CCalcEngine::DigitGroupingStringToGroupingVector(wstring_view g // If we found a grouping and aren't at the end of the string yet, // jump to the next position in the string (the ';'). // The loop will then increment us to the next character, which should be a number. - if (next && (static_cast(next - groupingString.data()) < groupingString.length())) + if (next && (static_cast(next - begin) < groupingString.length())) { itr = next; } @@ -312,7 +314,7 @@ wstring CCalcEngine::GroupDigits(wstring_view delimiter, vector const& ritr = displayString.rbegin(); } - wstringstream groupedStream{}; + wstring result; uint32_t groupingSize = 0; auto groupItr = grouping.begin(); @@ -323,7 +325,7 @@ wstring CCalcEngine::GroupDigits(wstring_view delimiter, vector const& auto reverse_end = displayString.rend() - (isNumNegative ? 1 : 0); while (ritr != reverse_end) { - groupedStream << *ritr++; + result += *ritr++; groupingSize++; // If a group is complete, add a separator @@ -332,7 +334,7 @@ wstring CCalcEngine::GroupDigits(wstring_view delimiter, vector const& // - we are at the end of the digit string if (currGrouping != 0 && (groupingSize % currGrouping) == 0 && ritr != reverse_end) { - groupedStream << wstring{ delimiter }; + result += delimiter; groupingSize = 0; // reset for a new group // Shift the grouping to next values if they exist @@ -364,11 +366,10 @@ wstring CCalcEngine::GroupDigits(wstring_view delimiter, vector const& // now copy the negative sign if it is there if (isNumNegative) { - groupedStream << displayString[0]; + result += displayString[0]; } - auto groupedString = groupedStream.str(); - wstring result(groupedString.rbegin(), groupedString.rend()); + reverse(result.begin(), result.end()); // Add the right (fractional or exponential) part of the number to the final string. if (hasDecimal) { diff --git a/src/CalcManager/CEngine/scifunc.cpp b/src/CalcManager/CEngine/scifunc.cpp index 5684ce43..15ef164b 100644 --- a/src/CalcManager/CEngine/scifunc.cpp +++ b/src/CalcManager/CEngine/scifunc.cpp @@ -46,8 +46,8 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } break; - // Rotate Left with hi bit wrapped over to lo bit case IDC_ROL: + case IDC_ROLC: if (m_fIntegerMode) { result = Integer(rat); @@ -55,14 +55,23 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r uint64_t w64Bits = result.ToUInt64_t(); uint64_t msb = (w64Bits >> (m_dwWordBitWidth - 1)) & 1; w64Bits <<= 1; // LShift by 1 - w64Bits |= msb; // Set the prev Msb as the current Lsb + + if (op == IDC_ROL) + { + w64Bits |= msb; // Set the prev Msb as the current Lsb + } + else + { + w64Bits |= m_carryBit; // Set the carry bit as the LSB + m_carryBit = msb; // Store the msb as the next carry bit + } result = w64Bits; } break; - // Rotate right with lo bit wrapped over to hi bit case IDC_ROR: + case IDC_RORC: if (m_fIntegerMode) { result = Integer(rat); @@ -70,7 +79,16 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r uint64_t w64Bits = result.ToUInt64_t(); uint64_t lsb = ((w64Bits & 0x01) == 1) ? 1 : 0; w64Bits >>= 1; // RShift by 1 - w64Bits |= (lsb << (m_dwWordBitWidth - 1)); + + if (op == IDC_ROR) + { + w64Bits |= (lsb << (m_dwWordBitWidth - 1)); + } + else + { + w64Bits |= (m_carryBit << (m_dwWordBitWidth - 1)); + m_carryBit = lsb; + } result = w64Bits; } @@ -133,6 +151,48 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } break; + case IDC_SEC: + if (!m_fIntegerMode) + { + result = m_bInv ? ACos(Invert(rat), m_angletype) : Invert(Cos(rat, m_angletype)); + } + break; + + case IDC_CSC: + if (!m_fIntegerMode) + { + result = m_bInv ? ASin(Invert(rat), m_angletype) : Invert(Sin(rat, m_angletype)); + } + break; + + case IDC_COT: + if (!m_fIntegerMode) + { + result = m_bInv ? ATan(Invert(rat), m_angletype) : Invert(Tan(rat, m_angletype)); + } + break; + + case IDC_SECH: + if (!m_fIntegerMode) + { + result = m_bInv ? ACosh(Invert(rat)) : Invert(Cosh(rat)); + } + break; + + case IDC_CSCH: + if (!m_fIntegerMode) + { + result = m_bInv ? ASinh(Invert(rat)) : Invert(Sinh(rat)); + } + break; + + case IDC_COTH: + if (!m_fIntegerMode) + { + result = m_bInv ? ATanh(Invert(rat)) : Invert(Tanh(rat)); + } + break; + case IDC_REC: /* Reciprocal. */ result = Invert(rat); break; @@ -158,6 +218,10 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r result = Pow(10, rat); break; + case IDC_POW2: + result = Pow(2, rat); + break; + case IDC_LN: /* Functions for natural log. */ result = m_bInv ? Exp(rat) : Log(rat); break; @@ -202,6 +266,18 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } break; } + case IDC_CEIL: + result = (Frac(rat) > 0) ? Integer(rat + 1) : Integer(rat); + break; + + case IDC_FLOOR: + result = (Frac(rat) < 0) ? Integer(rat - 1 ) : Integer(rat); + break; + + case IDC_ABS: + result = Abs(rat); + break; + } // end switch( op ) } catch (uint32_t nErrCode) diff --git a/src/CalcManager/CEngine/scioper.cpp b/src/CalcManager/CEngine/scioper.cpp index e41aee21..6ea3956b 100644 --- a/src/CalcManager/CEngine/scioper.cpp +++ b/src/CalcManager/CEngine/scioper.cpp @@ -28,6 +28,14 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa result ^= rhs; break; + case IDC_NAND: + result = (result & rhs) ^ m_chopNumbers[m_numwidth]; + break; + + case IDC_NOR: + result = (result | rhs) ^ m_chopNumbers[m_numwidth]; + break; + case IDC_RSHF: { if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0 @@ -52,7 +60,16 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa } break; } + case IDC_RSHFL: + { + if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0 + { + throw CALC_E_NORESULT; + } + result = rhs >> result; + break; + } case IDC_LSHF: if (m_fIntegerMode && result >= m_dwWordBitWidth) // Lsh/Rsh >= than current word size is always 0 { @@ -140,6 +157,10 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa case IDC_ROOT: // Calculates rhs to the result(th) root. result = Root(rhs, result); break; + + case IDC_LOGBASEX: + result = (Log(result) / Log(rhs)); + break; } } catch (uint32_t dwErrCode) diff --git a/src/CalcManager/CalcManager.vcxproj b/src/CalcManager/CalcManager.vcxproj index 7022cd3e..b30b3976 100644 --- a/src/CalcManager/CalcManager.vcxproj +++ b/src/CalcManager/CalcManager.vcxproj @@ -78,24 +78,32 @@ false true v142 + NativeRecommendedRules.ruleset + true StaticLibrary false true v142 + NativeRecommendedRules.ruleset + true StaticLibrary false true v142 + NativeRecommendedRules.ruleset + true StaticLibrary false true v142 + NativeRecommendedRules.ruleset + true @@ -175,6 +183,7 @@ Level4 true pch.h + true Console @@ -209,6 +218,7 @@ Level4 true pch.h + true Console @@ -244,6 +254,7 @@ Level4 true pch.h + true Console @@ -278,6 +289,7 @@ Level4 true pch.h + true Console @@ -289,7 +301,6 @@ - diff --git a/src/CalcManager/CalcManager.vcxproj.filters b/src/CalcManager/CalcManager.vcxproj.filters index 53098917..ad7670a0 100644 --- a/src/CalcManager/CalcManager.vcxproj.filters +++ b/src/CalcManager/CalcManager.vcxproj.filters @@ -120,7 +120,6 @@ RatPack - Header Files diff --git a/src/CalcManager/CalculatorHistory.cpp b/src/CalcManager/CalculatorHistory.cpp index 14a94a8c..6c9a002b 100644 --- a/src/CalcManager/CalculatorHistory.cpp +++ b/src/CalcManager/CalculatorHistory.cpp @@ -7,25 +7,48 @@ using namespace std; using namespace CalculationManager; +namespace +{ + static wstring GetGeneratedExpression(const vector>& tokens) + { + wstring expression; + bool isFirst = true; + + for (auto const& token : tokens) + { + if (isFirst) + { + isFirst = false; + } + else + { + expression += L' '; + } + expression.append(token.first); + } + + return expression; + } +} + CalculatorHistory::CalculatorHistory(size_t maxSize) : m_maxHistorySize(maxSize) { } unsigned int CalculatorHistory::AddToHistory( - _In_ shared_ptr>> const& tokens, - _In_ shared_ptr>> const& commands, - _In_ wstring_view result) + _In_ shared_ptr>> const& tokens, + _In_ shared_ptr>> const& commands, + wstring_view result) { unsigned int addedIndex; - wstring generatedExpression; shared_ptr spHistoryItem = make_shared(); spHistoryItem->historyItemVector.spTokens = tokens; spHistoryItem->historyItemVector.spCommands = commands; // to be changed when pszexp is back - tokens->GetString(&generatedExpression); + wstring generatedExpression = GetGeneratedExpression(*tokens); // Prefixing and suffixing the special Unicode markers to ensure that the expression // in the history doesn't get broken for RTL languages spHistoryItem->historyItemVector.expression = L'\u202d' + generatedExpression + L'\u202c'; @@ -47,7 +70,7 @@ unsigned int CalculatorHistory::AddItem(_In_ shared_ptr const& spHi return lastIndex; } -bool CalculatorHistory::RemoveItem(_In_ unsigned int uIdx) +bool CalculatorHistory::RemoveItem(unsigned int uIdx) { if (uIdx > m_historyItems.size() - 1) { @@ -63,17 +86,12 @@ vector> const& CalculatorHistory::GetHistory() return m_historyItems; } -shared_ptr const& CalculatorHistory::GetHistoryItem(_In_ unsigned int uIdx) +shared_ptr const& CalculatorHistory::GetHistoryItem(unsigned int uIdx) { assert(uIdx >= 0 && uIdx < m_historyItems.size()); return m_historyItems.at(uIdx); } -CalculatorHistory::~CalculatorHistory(void) -{ - ClearHistory(); -} - void CalculatorHistory::ClearHistory() { m_historyItems.clear(); diff --git a/src/CalcManager/CalculatorHistory.h b/src/CalcManager/CalculatorHistory.h index 75b74255..e8c874a0 100644 --- a/src/CalcManager/CalculatorHistory.h +++ b/src/CalcManager/CalculatorHistory.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once @@ -15,8 +15,8 @@ namespace CalculationManager struct HISTORYITEMVECTOR { - std::shared_ptr>> spTokens; - std::shared_ptr>> spCommands; + std::shared_ptr>> spTokens; + std::shared_ptr>> spCommands; std::wstring expression; std::wstring result; }; @@ -31,8 +31,8 @@ namespace CalculationManager public: CalculatorHistory(const size_t maxSize); unsigned int AddToHistory( - _In_ std::shared_ptr>> const& spTokens, - _In_ std::shared_ptr>> const& spCommands, + _In_ std::shared_ptr>> const& spTokens, + _In_ std::shared_ptr>> const& spCommands, std::wstring_view result); std::vector> const& GetHistory(); std::shared_ptr const& GetHistoryItem(unsigned int uIdx); @@ -43,7 +43,6 @@ namespace CalculationManager { return m_maxHistorySize; } - ~CalculatorHistory(void); private: std::vector> m_historyItems; diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index 12df63bb..8d6f1e51 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -75,14 +75,19 @@ namespace CalculationManager m_displayCallback->MemoryItemChanged(indexOfMemory); } + void CalculatorManager::InputChanged() + { + m_displayCallback->InputChanged(); + } + /// /// Call the callback function using passed in IDisplayHelper. /// Used to set the expression display value on ViewModel /// /// wstring representing expression to be displayed void CalculatorManager::SetExpressionDisplay( - _Inout_ shared_ptr>> const& tokens, - _Inout_ shared_ptr>> const& commands) + _Inout_ shared_ptr>> const& tokens, + _Inout_ shared_ptr>> const& commands) { if (!m_inHistoryItemLoadMode) { @@ -240,6 +245,7 @@ namespace CalculationManager m_savedCommands.push_back(MapCommandForSerialize(command)); } m_savedDegreeMode = m_currentDegreeMode; + InputChanged(); return; } @@ -283,6 +289,30 @@ namespace CalculationManager m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandTANH)); break; + case Command::CommandASEC: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSEC)); + break; + case Command::CommandACSC: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCSC)); + break; + case Command::CommandACOT: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOT)); + break; + case Command::CommandASECH: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSECH)); + break; + case Command::CommandACSCH: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCSCH)); + break; + case Command::CommandACOTH: + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOTH)); + break; case Command::CommandFE: m_isExponentialFormat = !m_isExponentialFormat; [[fallthrough]]; @@ -290,6 +320,8 @@ namespace CalculationManager m_currentCalculatorEngine->ProcessCommand(static_cast(command)); break; } + + InputChanged(); } /// @@ -330,6 +362,7 @@ namespace CalculationManager { m_currentCalculatorEngine->PersistedMemObject(m_persistedPrimaryValue); m_currentCalculatorEngine->ProcessCommand(IDC_RECALL); + InputChanged(); } /// @@ -376,6 +409,7 @@ namespace CalculationManager this->MemorizedNumberSelect(indexOfMemory); m_currentCalculatorEngine->ProcessCommand(IDC_RECALL); + InputChanged(); } /// @@ -606,16 +640,16 @@ namespace CalculationManager if (pHistory) { pHistory->ClearHistory(); - for (unsigned int i = 0; i < history.size(); ++i) + for (auto const& historyItem : history) { - pHistory->AddItem(history[i]); + pHistory->AddItem(historyItem); } } } - wstring CalculatorManager::GetResultForRadix(uint32_t radix, int32_t precision) + wstring CalculatorManager::GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix) { - return m_currentCalculatorEngine ? m_currentCalculatorEngine->GetCurrentResultForRadix(radix, precision) : L""; + return m_currentCalculatorEngine ? m_currentCalculatorEngine->GetCurrentResultForRadix(radix, precision, groupDigitsPerRadix) : L""; } void CalculatorManager::SetPrecision(int32_t precision) @@ -638,100 +672,13 @@ namespace CalculationManager return m_currentCalculatorEngine->FInRecordingState() ? true : false; } + bool CalculatorManager::IsInputEmpty() + { + return m_currentCalculatorEngine->IsInputEmpty(); + } + void CalculatorManager::SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode) { m_inHistoryItemLoadMode = isHistoryItemLoadMode; } - - /// - /// Serialize Rational to vector of long - /// How Rational is serialized : - /// Serialized Rational.P(Number) + Serialized Rational.Q(Number) - /// How Number is saved : - /// [0] = Rational.P.Sign - /// [1] = Rational.P.Mantissa.size - /// [2] = Rational.P.Exp - /// [3] = Rational.P.Mantissa[0] - /// [4] = Rational.P.Mantissa[1] - /// ... - /// [2 + Rational.P.Mantissa.size] = Rational.P.Mantissa[size - 1] - /// - /// Rational number to be serialized - vector CalculatorManager::SerializeRational(Rational const& rat) - { - vector serializedRational{}; - - auto serialP = SerializeNumber(rat.P()); - serializedRational.insert(serializedRational.end(), serialP.begin(), serialP.end()); - - auto serialQ = SerializeNumber(rat.Q()); - serializedRational.insert(serializedRational.end(), serialQ.begin(), serialQ.end()); - - return serializedRational; - } - - /// - /// DeserializeRational vector and construct a Rational - /// How Rational is serialized : - /// Serialized Rational.P(Number) + Serialized Rational.Q(Number) - /// - Rational CalculatorManager::DeSerializeRational(vector::const_iterator itr) - { - auto p = DeSerializeNumber(itr); - auto q = DeSerializeNumber(itr + SERIALIZED_NUMBER_MINSIZE + p.Mantissa().size()); - - return Rational(p, q); - } - - /// - /// Serialize Number to vector of long - /// How Number is saved : - /// [0] = Number.Sign - /// [1] = Number.Mantissa.size - /// [2] = Number.Exp - /// [3] = Number.Mantissa[0] - /// [4] = Number.Mantissa[1] - /// ... - /// [2 + Number.Mantissa.size] = Number.Mantissa[size - 1] - /// - /// Number to be serialized - vector CalculatorManager::SerializeNumber(Number const& num) - { - vector serializedNumber{}; - - serializedNumber.push_back(num.Sign()); - serializedNumber.push_back(static_cast(num.Mantissa().size())); - serializedNumber.push_back(num.Exp()); - for (auto const& digit : num.Mantissa()) - { - serializedNumber.push_back(digit); - } - - return serializedNumber; - } - - /// - /// DeserializeNumber vector and construct a Number - /// How Number is saved : - /// [0] = Number.Sign - /// [1] = Number.Mantissa.size - /// [2] = Number.Exp - /// [3] = Number.Mantissa[0] - /// [4] = Number.Mantissa[1] - /// ... - /// [2 + Number.Mantissa.size] = Number.Mantissa[size - 1] - /// - Number CalculatorManager::DeSerializeNumber(vector::const_iterator itr) - { - int32_t sign = *itr; - uint32_t size = *(itr + 1); - int32_t exp = *(itr + 2); - vector mant{}; - for (size_t i = 0; i < size; ++i) - { - mant.emplace_back(*(itr + 3 + i)); - } - - return Number{ sign, exp, mant }; - } } diff --git a/src/CalcManager/CalculatorManager.h b/src/CalcManager/CalculatorManager.h index d34d2e35..dd30c16a 100644 --- a/src/CalcManager/CalculatorManager.h +++ b/src/CalcManager/CalculatorManager.h @@ -76,12 +76,6 @@ namespace CalculationManager void LoadPersistedPrimaryValue(); - static std::vector SerializeRational(CalcEngine::Rational const& rat); - static CalcEngine::Rational DeSerializeRational(std::vector::const_iterator itr); - - static std::vector SerializeNumber(CalcEngine::Number const& num); - static CalcEngine::Number DeSerializeNumber(std::vector::const_iterator itr); - std::shared_ptr m_pStdHistory; std::shared_ptr m_pSciHistory; CalculatorHistory* m_pHistory; @@ -91,8 +85,8 @@ namespace CalculationManager void SetPrimaryDisplay(_In_ const std::wstring& displayString, _In_ bool isError) override; void SetIsInError(bool isError) override; void SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands) override; + _Inout_ std::shared_ptr>> const& tokens, + _Inout_ std::shared_ptr>> const& commands) override; void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override; void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override; @@ -101,8 +95,8 @@ namespace CalculationManager void MaxDigitsReached() override; void BinaryOperatorReceived() override; void MemoryItemChanged(unsigned int indexOfMemory) override; - - CalculatorManager(ICalcDisplay* displayCallback, IResourceProvider* resourceProvider); + void InputChanged() override; + CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider); void Reset(bool clearMemory = true); void SetStandardMode(); @@ -118,13 +112,14 @@ namespace CalculationManager void MemorizedNumberClearAll(); bool IsEngineRecording(); - std::vector GetSavedCommands() + bool IsInputEmpty(); + const std::vector& GetSavedCommands() const { return m_savedCommands; } void SetRadix(RADIX_TYPE iRadixType); void SetMemorizedNumbersString(); - std::wstring GetResultForRadix(uint32_t radix, int32_t precision); + std::wstring GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix); void SetPrecision(int32_t precision); void UpdateMaxIntDigits(); wchar_t DecimalSeparator(); diff --git a/src/CalcManager/CalculatorResource.h b/src/CalcManager/CalculatorResource.h index 5f360f35..8c4c049c 100644 --- a/src/CalcManager/CalculatorResource.h +++ b/src/CalcManager/CalculatorResource.h @@ -1,8 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once +#include + namespace CalculationManager { class IResourceProvider @@ -19,6 +21,6 @@ namespace CalculationManager // ids "sDecimal", "sThousand" and "sGrouping". See // https://technet.microsoft.com/en-us/library/cc782655(v=ws.10).aspx // for what these values refer to. - virtual std::wstring GetCEngineString(const std::wstring& id) = 0; + virtual std::wstring GetCEngineString(std::wstring_view id) = 0; }; } diff --git a/src/CalcManager/CalculatorVector.h b/src/CalcManager/CalculatorVector.h deleted file mode 100644 index 4a139c8e..00000000 --- a/src/CalcManager/CalculatorVector.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include -#include -#include "winerror_cross_platform.h" -#include "Ratpack/CalcErr.h" -#include // for std::out_of_range -#include "sal_cross_platform.h" // for SAL - -template -class CalculatorVector -{ -public: - ResultCode GetAt(_In_opt_ unsigned int index, _Out_ TType* item) - { - try - { - *item = m_vector.at(index); - } - catch (const std::out_of_range& /*ex*/) - { - return E_BOUNDS; - } - return S_OK; - } - - ResultCode GetSize(_Out_ unsigned int* size) - { - *size = static_cast(m_vector.size()); - return S_OK; - } - - ResultCode SetAt(_In_ unsigned int index, _In_opt_ TType item) - { - try - { - m_vector[index] = item; - } - catch (const std::out_of_range& /*ex*/) - { - return E_BOUNDS; - } - return S_OK; - } - - ResultCode RemoveAt(_In_ unsigned int index) - { - if (index < m_vector.size()) - { - m_vector.erase(m_vector.begin() + index); - } - else - { - return E_BOUNDS; - } - return S_OK; - } - - ResultCode InsertAt(_In_ unsigned int index, _In_ TType item) - { - try - { - auto iter = m_vector.begin() + index; - m_vector.insert(iter, item); - } - catch (const std::bad_alloc& /*ex*/) - { - return E_OUTOFMEMORY; - } - return S_OK; - } - - ResultCode Truncate(_In_ unsigned int index) - { - if (index < m_vector.size()) - { - auto startIter = m_vector.begin() + index; - m_vector.erase(startIter, m_vector.end()); - } - else - { - return E_BOUNDS; - } - return S_OK; - } - - ResultCode Append(_In_opt_ TType item) - { - try - { - m_vector.push_back(item); - } - catch (const std::bad_alloc& /*ex*/) - { - return E_OUTOFMEMORY; - } - return S_OK; - } - - ResultCode RemoveAtEnd() - { - m_vector.erase(--(m_vector.end())); - return S_OK; - } - - ResultCode Clear() - { - m_vector.clear(); - return S_OK; - } - - ResultCode GetString(_Out_ std::wstring* expression) - { - unsigned int nTokens = 0; - ResultCode hr = this->GetSize(&nTokens); - if (SUCCEEDED(hr)) - { - - std::pair currentPair; - for (unsigned int i = 0; i < nTokens; i++) - { - hr = this->GetAt(i, ¤tPair); - if (SUCCEEDED(hr)) - { - expression->append(currentPair.first); - - if (i != (nTokens - 1)) - { - expression->append(L" "); - } - } - } - - std::wstring expressionSuffix{}; - hr = GetExpressionSuffix(&expressionSuffix); - if (SUCCEEDED(hr)) - { - expression->append(expressionSuffix); - } - } - - return hr; - } - - ResultCode GetExpressionSuffix(_Out_ std::wstring* suffix) - { - *suffix = L" ="; - return S_OK; - } - -private: - std::vector m_vector; -}; diff --git a/src/CalcManager/Command.h b/src/CalcManager/Command.h index 3dd508ed..4331ddf7 100644 --- a/src/CalcManager/Command.h +++ b/src/CalcManager/Command.h @@ -97,6 +97,7 @@ namespace CalculationManager CommandROL = 99, CommandROR = 100, CommandCOM = 101, + CommandSIN = 102, CommandCOS = 103, CommandTAN = 104, @@ -151,6 +152,34 @@ namespace CalculationManager CommandINV = 146, CommandSET_RESULT = 147, + CommandSEC = 400, + CommandASEC = 401, + CommandCSC = 402, + CommandACSC = 403, + CommandCOT = 404, + CommandACOT = 405, + + CommandSECH = 406, + CommandASECH = 407, + CommandCSCH = 408, + CommandACSCH = 409, + CommandCOTH = 410, + CommandACOTH = 411, + + CommandPOW2 = 412, // 2 ^ x + CommandAbs = 413, + CommandFloor = 414, + CommandCeil = 415, + CommandROLC = 416, + CommandRORC = 417, + CommandLogBaseX = 500, + CommandNand = 501, + CommandNor = 502, + + CommandRSHFL = 505, + CommandRand = 600, + CommandEuler = 601, + CommandAnd = 86, CommandOR = 87, CommandNot = 101, diff --git a/src/CalcManager/ExpressionCommand.cpp b/src/CalcManager/ExpressionCommand.cpp index 2d0547c6..628805fb 100644 --- a/src/CalcManager/ExpressionCommand.cpp +++ b/src/CalcManager/ExpressionCommand.cpp @@ -3,7 +3,6 @@ #include #include "Header Files/CCommand.h" -#include "CalculatorVector.h" #include "ExpressionCommand.h" using namespace std; @@ -35,18 +34,18 @@ void CParentheses::Accept(_In_ ISerializeCommandVisitor& commandVisitor) CUnaryCommand::CUnaryCommand(int command) { - m_command = make_shared>(); - m_command->Append(command); + m_command = make_shared>(); + m_command->push_back(command); } CUnaryCommand::CUnaryCommand(int command1, int command2) { - m_command = make_shared>(); - m_command->Append(command1); - m_command->Append(command2); + m_command = make_shared>(); + m_command->push_back(command1); + m_command->push_back(command2); } -const shared_ptr>& CUnaryCommand::GetCommands() const +const shared_ptr>& CUnaryCommand::GetCommands() const { return m_command; } @@ -58,15 +57,15 @@ CalculationManager::CommandType CUnaryCommand::GetCommandType() const void CUnaryCommand::SetCommand(int command) { - m_command->Clear(); - m_command->Append(command); + m_command->clear(); + m_command->push_back(command); } void CUnaryCommand::SetCommands(int command1, int command2) { - m_command->Clear(); - m_command->Append(command1); - m_command->Append(command2); + m_command->clear(); + m_command->push_back(command1); + m_command->push_back(command2); } void CUnaryCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor) @@ -99,7 +98,7 @@ void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor) commandVisitor.Visit(*this); } -COpndCommand::COpndCommand(shared_ptr> const& commands, bool fNegative, bool fDecimal, bool fSciFmt) +COpndCommand::COpndCommand(shared_ptr> const& commands, bool fNegative, bool fDecimal, bool fSciFmt) : m_commands(commands) , m_fNegative(fNegative) , m_fSciFmt(fSciFmt) @@ -115,27 +114,25 @@ void COpndCommand::Initialize(Rational const& rat) m_fInitialized = true; } -const shared_ptr>& COpndCommand::GetCommands() const +const shared_ptr>& COpndCommand::GetCommands() const { return m_commands; } -void COpndCommand::SetCommands(shared_ptr> const& commands) +void COpndCommand::SetCommands(shared_ptr> const& commands) { m_commands = commands; } void COpndCommand::AppendCommand(int command) { - unsigned int nCommands; - m_commands->GetSize(&nCommands); if (m_fSciFmt) { ClearAllAndAppendCommand(static_cast(command)); } else { - m_commands->Append(command); + m_commands->push_back(command); } if (command == IDC_PNT) @@ -146,14 +143,8 @@ void COpndCommand::AppendCommand(int command) void COpndCommand::ToggleSign() { - unsigned int commandCount; - m_commands->GetSize(&commandCount); - - for (unsigned int i = 0; i < commandCount; i++) + for (int nOpCode : *m_commands) { - int nOpCode; - m_commands->GetAt(i, &nOpCode); - if (nOpCode != IDC_0) { m_fNegative = !m_fNegative; @@ -170,8 +161,7 @@ void COpndCommand::RemoveFromEnd() } else { - unsigned int nCommands; - m_commands->GetSize(&nCommands); + const size_t nCommands = m_commands->size(); if (nCommands == 1) { @@ -179,13 +169,14 @@ void COpndCommand::RemoveFromEnd() } else { - int nOpCode; - m_commands->GetAt(nCommands - 1, &nOpCode); + int nOpCode = m_commands->at(nCommands - 1); + if (nOpCode == IDC_PNT) { m_fDecimal = false; } - m_commands->RemoveAt(nCommands - 1); + + m_commands->pop_back(); } } } @@ -212,8 +203,8 @@ CalculationManager::CommandType COpndCommand::GetCommandType() const void COpndCommand::ClearAllAndAppendCommand(CalculationManager::Command command) { - m_commands->Clear(); - m_commands->Append(static_cast(command)); + m_commands->clear(); + m_commands->push_back(static_cast(command)); m_fSciFmt = false; m_fNegative = false; m_fDecimal = false; @@ -223,31 +214,29 @@ const wstring& COpndCommand::GetToken(wchar_t decimalSymbol) { static const wchar_t chZero = L'0'; - unsigned int nCommands; - m_commands->GetSize(&nCommands); + const size_t nCommands = m_commands->size(); m_token.clear(); - int nOpCode; - for (unsigned int i = 0; i < nCommands; i++) + for (size_t i = 0; i < nCommands; i++) { - m_commands->GetAt(i, &nOpCode); + int nOpCode = (*m_commands)[i]; + if (nOpCode == IDC_PNT) { - m_token.append(wstring{ decimalSymbol }); + m_token += decimalSymbol; } else if (nOpCode == IDC_EXP) { - m_token.append(&chExp); - int nextOpCode; - m_commands->GetAt(i + 1, &nextOpCode); + m_token += chExp; + int nextOpCode = m_commands->at(i + 1); if (nextOpCode != IDC_SIGN) { - m_token.append(&chPlus); + m_token += chPlus; } } else if (nOpCode == IDC_SIGN) { - m_token.append(&chNegate); + m_token += chNegate; } else { @@ -257,7 +246,7 @@ const wstring& COpndCommand::GetToken(wchar_t decimalSymbol) } // Remove zeros - for (unsigned int i = 0; i < m_token.size(); i++) + for (size_t i = 0; i < m_token.size(); i++) { if (m_token.at(i) != chZero) { @@ -272,29 +261,26 @@ const wstring& COpndCommand::GetToken(wchar_t decimalSymbol) if (m_fNegative) { - m_token.insert(0, &chNegate); + m_token.insert(0, 1, chNegate); } return m_token; } } - m_token.clear(); - m_token.append(&chZero); + m_token = chZero; return m_token; } wstring COpndCommand::GetString(uint32_t radix, int32_t precision) { - wstring result{}; - if (m_fInitialized) { - result = m_value.ToString(radix, eNUMOBJ_FMT::FMT_FLOAT, precision); + return m_value.ToString(radix, eNUMOBJ_FMT::FMT_FLOAT, precision); } - return result; + return wstring{}; } void COpndCommand::Accept(_In_ ISerializeCommandVisitor& commandVisitor) diff --git a/src/CalcManager/ExpressionCommand.h b/src/CalcManager/ExpressionCommand.h index 91d41e60..d8ab7ec0 100644 --- a/src/CalcManager/ExpressionCommand.h +++ b/src/CalcManager/ExpressionCommand.h @@ -23,14 +23,14 @@ class CUnaryCommand final : public IUnaryCommand public: CUnaryCommand(int command); CUnaryCommand(int command1, int command2); - const std::shared_ptr>& GetCommands() const override; + const std::shared_ptr>& GetCommands() const override; CalculationManager::CommandType GetCommandType() const override; void SetCommand(int command) override; void SetCommands(int command1, int command2) override; void Accept(_In_ ISerializeCommandVisitor& commandVisitor) override; private: - std::shared_ptr> m_command; + std::shared_ptr> m_command; }; class CBinaryCommand final : public IBinaryCommand @@ -49,11 +49,11 @@ private: class COpndCommand final : public IOpndCommand { public: - COpndCommand(std::shared_ptr> const& commands, bool fNegative, bool fDecimal, bool fSciFmt); + COpndCommand(std::shared_ptr> const& commands, bool fNegative, bool fDecimal, bool fSciFmt); void Initialize(CalcEngine::Rational const& rat); - const std::shared_ptr>& GetCommands() const override; - void SetCommands(std::shared_ptr> const& commands) override; + const std::shared_ptr>& GetCommands() const override; + void SetCommands(std::shared_ptr> const& commands) override; void AppendCommand(int command) override; void ToggleSign() override; void RemoveFromEnd() override; @@ -66,7 +66,7 @@ public: std::wstring GetString(uint32_t radix, int32_t precision); private: - std::shared_ptr> m_commands; + std::shared_ptr> m_commands; bool m_fNegative; bool m_fSciFmt; bool m_fDecimal; diff --git a/src/CalcManager/ExpressionCommandInterface.h b/src/CalcManager/ExpressionCommandInterface.h index 9115316d..4ea9b81b 100644 --- a/src/CalcManager/ExpressionCommandInterface.h +++ b/src/CalcManager/ExpressionCommandInterface.h @@ -4,7 +4,7 @@ #pragma once #include // for std::shared_ptr -#include "CalculatorVector.h" +#include #include "Command.h" class ISerializeCommandVisitor; @@ -25,7 +25,7 @@ public: class IUnaryCommand : public IOperatorCommand { public: - virtual const std::shared_ptr>& GetCommands() const = 0; + virtual const std::shared_ptr>& GetCommands() const = 0; virtual void SetCommands(int command1, int command2) = 0; }; @@ -39,7 +39,7 @@ public: class IOpndCommand : public IExpressionCommand { public: - virtual const std::shared_ptr>& GetCommands() const = 0; + virtual const std::shared_ptr>& GetCommands() const = 0; virtual void AppendCommand(int command) = 0; virtual void ToggleSign() = 0; virtual void RemoveFromEnd() = 0; @@ -47,7 +47,7 @@ public: virtual bool IsSciFmt() const = 0; virtual bool IsDecimalPresent() const = 0; virtual const std::wstring& GetToken(wchar_t decimalSymbol) = 0; - virtual void SetCommands(std::shared_ptr> const& commands) = 0; + virtual void SetCommands(std::shared_ptr> const& commands) = 0; }; class IParenthesisCommand : public IExpressionCommand diff --git a/src/CalcManager/Header Files/CCommand.h b/src/CalcManager/Header Files/CCommand.h index 6366b45a..f6d74d25 100644 --- a/src/CalcManager/Header Files/CCommand.h +++ b/src/CalcManager/Header Files/CCommand.h @@ -81,6 +81,7 @@ #define IDC_ROL 99 #define IDC_ROR 100 #define IDC_COM 101 + #define IDC_SIN 102 #define IDC_COS 103 #define IDC_TAN 104 @@ -136,7 +137,44 @@ #define IDC_INV 146 #define IDC_SET_RESULT 147 -#define IDC_LASTCONTROL IDC_SET_RESULT +#define IDC_STRING_MAPPED_VALUES 400 +#define IDC_UNARYEXTENDEDFIRST IDC_STRING_MAPPED_VALUES +#define IDC_SEC 400 // Secant +// 401 reserved for inverse +#define IDC_CSC 402 // Cosecant +// 403 reserved for inverse +#define IDC_COT 404 // Cotangent +// 405 reserved for inverse + +#define IDC_SECH 406 //Hyperbolic Secant +// 407 reserved for inverse +#define IDC_CSCH 408 //Hyperbolic Cosecant +// 409 reserved for inverse +#define IDC_COTH 410 //Hyperbolic Cotangent +// 411 reserved for inverse + +#define IDC_POW2 412 // 2 ^ x +#define IDC_ABS 413 // Absolute Value +#define IDC_FLOOR 414 // Floor +#define IDC_CEIL 415 // Ceiling + +#define IDC_ROLC 416 // Rotate Left Circular +#define IDC_RORC 417 // Rotate Right Circular + +#define IDC_UNARYEXTENDEDLAST IDC_RORC + +#define IDC_LASTCONTROL IDC_CEIL + +#define IDC_BINARYEXTENDEDFIRST 500 +#define IDC_LOGBASEX 500 // logx(y) +#define IDC_NAND 501 // Nand +#define IDC_NOR 502 // Nor + +#define IDC_RSHFL 505 //Right Shift Logical +#define IDC_BINARYEXTENDEDLAST IDC_RSHFL + +#define IDC_RAND 600 // Random +#define IDC_EULER 601 // e Constant #define IDC_BINEDITSTART 700 #define IDC_BINPOS0 700 diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/Header Files/CalcEngine.h index 9da57627..26b80515 100644 --- a/src/CalcManager/Header Files/CalcEngine.h +++ b/src/CalcManager/Header Files/CalcEngine.h @@ -14,10 +14,10 @@ * \****************************************************************************/ +#include #include "CCommand.h" #include "EngineStrings.h" #include "../Command.h" -#include "../CalculatorVector.h" #include "../ExpressionCommand.h" #include "RadixType.h" #include "History.h" // for History Collector @@ -68,6 +68,10 @@ public: { return m_bError; } + bool IsInputEmpty() + { + return m_input.IsEmpty() && (m_numberString.empty() || m_numberString == L"0"); + } bool FInRecordingState() { return m_bRecord; @@ -75,7 +79,7 @@ public: void SettingsChanged(); bool IsCurrentTooBigForTrig(); int GetCurrentRadix(); - std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision); + std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix); void ChangePrecision(int32_t precision) { m_precision = precision; @@ -94,7 +98,7 @@ public: { return s_engineStrings[std::to_wstring(ids)]; } - static std::wstring_view GetString(std::wstring ids) + static std::wstring_view GetString(std::wstring_view ids) { return s_engineStrings[ids]; } @@ -103,6 +107,7 @@ public: return GetString(IdStrFromCmdId(nOpCode)); } static std::wstring_view OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype); + static std::wstring_view OpCodeToBinaryString(int nOpCode, bool isIntegerMode); private: bool m_fPrecedence; @@ -147,11 +152,16 @@ private: NUM_WIDTH m_numwidth; // one of qword, dword, word or byte mode. int32_t m_dwWordBitWidth; // # of bits in currently selected word size + std::unique_ptr m_randomGeneratorEngine; + std::unique_ptr> m_distr; + + uint64_t m_carryBit; + CHistoryCollector m_HistoryCollector; // Accumulator of each line of history as various commands are processed std::array m_chopNumbers; // word size enforcement std::array m_maxDecimalValueStrings; // maximum values represented by a given word width based off m_chopNumbers - static std::unordered_map s_engineStrings; // the string table shared across all instances + static std::unordered_map s_engineStrings; // the string table shared across all instances wchar_t m_decimalSeparator; wchar_t m_groupSeparator; @@ -165,12 +175,14 @@ private: void DisplayAnnounceBinaryOperator(); void SetPrimaryDisplay(const std::wstring& szText, bool isError = false); void ClearTemporaryValues(); + void ClearDisplay(); CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat); CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op); CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs); void SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth); int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth); uint32_t NRadixFromRadixType(RADIX_TYPE radixtype); + double GenerateRandomNumber(); bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno); void CheckAndAddLastBinOpToHistory(bool addToHistory = true); diff --git a/src/CalcManager/Header Files/CalcInput.h b/src/CalcManager/Header Files/CalcInput.h index 045cdb89..b798d061 100644 --- a/src/CalcManager/Header Files/CalcInput.h +++ b/src/CalcManager/Header Files/CalcInput.h @@ -66,6 +66,7 @@ namespace CalcEngine bool TryBeginExponent(); void Backspace(); void SetDecimalSymbol(wchar_t decSymbol); + bool IsEmpty(); std::wstring ToString(uint32_t radix); Rational ToRational(uint32_t radix, int32_t precision); diff --git a/src/CalcManager/Header Files/EngineStrings.h b/src/CalcManager/Header Files/EngineStrings.h index fffebf0d..958c828b 100644 --- a/src/CalcManager/Header Files/EngineStrings.h +++ b/src/CalcManager/Header Files/EngineStrings.h @@ -87,7 +87,6 @@ inline constexpr auto SIDS_XPOW3 = L"32"; inline constexpr auto SIDS_NFACTORIAL = L"33"; inline constexpr auto SIDS_RECIPROCAL = L"34"; inline constexpr auto SIDS_DMS = L"35"; -inline constexpr auto SIDS_CUBEROOT = L"36"; inline constexpr auto SIDS_POWTEN = L"37"; inline constexpr auto SIDS_PERCENT = L"38"; inline constexpr auto SIDS_SCIENTIFIC_NOTATION = L"39"; @@ -172,125 +171,193 @@ inline constexpr auto SIDS_ERR_UNEX_END = L"117"; inline constexpr auto SIDS_ERR_SG_INV_ERROR = L"118"; inline constexpr auto SIDS_ERR_INPUT_OVERFLOW = L"119"; inline constexpr auto SIDS_ERR_OUTPUT_OVERFLOW = L"120"; +inline constexpr auto SIDS_SECD = L"SecDeg"; +inline constexpr auto SIDS_SECR = L"SecRad"; +inline constexpr auto SIDS_SECG = L"SecGrad"; +inline constexpr auto SIDS_ASECD = L"InverseSecDeg"; +inline constexpr auto SIDS_ASECR = L"InverseSecRad"; +inline constexpr auto SIDS_ASECG = L"InverseSecGrad"; +inline constexpr auto SIDS_CSCD = L"CscDeg"; +inline constexpr auto SIDS_CSCR = L"CscRad"; +inline constexpr auto SIDS_CSCG = L"CscGrad"; +inline constexpr auto SIDS_ACSCD = L"InverseCscDeg"; +inline constexpr auto SIDS_ACSCR = L"InverseCscRad"; +inline constexpr auto SIDS_ACSCG = L"InverseCscGrad"; +inline constexpr auto SIDS_COTD = L"CotDeg"; +inline constexpr auto SIDS_COTR = L"CotRad"; +inline constexpr auto SIDS_COTG = L"CotGrad"; +inline constexpr auto SIDS_ACOTD = L"InverseCotDeg"; +inline constexpr auto SIDS_ACOTR = L"InverseCotRad"; +inline constexpr auto SIDS_ACOTG = L"InverseCotGrad"; +inline constexpr auto SIDS_SECH = L"Sech"; +inline constexpr auto SIDS_ASECH = L"InverseSech"; +inline constexpr auto SIDS_CSCH = L"Csch"; +inline constexpr auto SIDS_ACSCH = L"InverseCsch"; +inline constexpr auto SIDS_COTH = L"Coth"; +inline constexpr auto SIDS_ACOTH = L"InverseCoth"; +inline constexpr auto SIDS_TWOPOWX = L"TwoPowX"; +inline constexpr auto SIDS_LOGBASEX = L"LogBaseX"; +inline constexpr auto SIDS_ABS = L"Abs"; +inline constexpr auto SIDS_FLOOR = L"Floor"; +inline constexpr auto SIDS_CEIL = L"Ceil"; +inline constexpr auto SIDS_NAND = L"Nand"; +inline constexpr auto SIDS_NOR = L"Nor"; +inline constexpr auto SIDS_CUBEROOT = L"CubeRoot"; +inline constexpr auto SIDS_PROGRAMMER_MOD = L"ProgrammerMod"; // Include the resource key ID from above into this vector to load it into memory for the engine to use -inline constexpr std::array g_sids = { SIDS_PLUS_MINUS, - SIDS_C, - SIDS_CE, - SIDS_BACKSPACE, - SIDS_DECIMAL_SEPARATOR, - SIDS_EMPTY_STRING, - SIDS_AND, - SIDS_OR, - SIDS_XOR, - SIDS_LSH, - SIDS_RSH, - SIDS_DIVIDE, - SIDS_MULTIPLY, - SIDS_PLUS, - SIDS_MINUS, - SIDS_MOD, - SIDS_YROOT, - SIDS_POW_HAT, - SIDS_INT, - SIDS_ROL, - SIDS_ROR, - SIDS_NOT, - SIDS_SIN, - SIDS_COS, - SIDS_TAN, - SIDS_SINH, - SIDS_COSH, - SIDS_TANH, - SIDS_LN, - SIDS_LOG, - SIDS_SQRT, - SIDS_XPOW2, - SIDS_XPOW3, - SIDS_NFACTORIAL, - SIDS_RECIPROCAL, - SIDS_DMS, - SIDS_CUBEROOT, - SIDS_POWTEN, - SIDS_PERCENT, - SIDS_SCIENTIFIC_NOTATION, - SIDS_PI, - SIDS_EQUAL, - SIDS_MC, - SIDS_MR, - SIDS_MS, - SIDS_MPLUS, - SIDS_MMINUS, - SIDS_EXP, - SIDS_OPEN_PAREN, - SIDS_CLOSE_PAREN, - SIDS_0, - SIDS_1, - SIDS_2, - SIDS_3, - SIDS_4, - SIDS_5, - SIDS_6, - SIDS_7, - SIDS_8, - SIDS_9, - SIDS_A, - SIDS_B, - SIDS_C, - SIDS_D, - SIDS_E, - SIDS_F, - SIDS_FRAC, - SIDS_SIND, - SIDS_COSD, - SIDS_TAND, - SIDS_ASIND, - SIDS_ACOSD, - SIDS_ATAND, - SIDS_SINR, - SIDS_COSR, - SIDS_TANR, - SIDS_ASINR, - SIDS_ACOSR, - SIDS_ATANR, - SIDS_SING, - SIDS_COSG, - SIDS_TANG, - SIDS_ASING, - SIDS_ACOSG, - SIDS_ATANG, - SIDS_ASINH, - SIDS_ACOSH, - SIDS_ATANH, - SIDS_POWE, - SIDS_POWTEN2, - SIDS_SQRT2, - SIDS_SQR, - SIDS_CUBE, - SIDS_CUBERT, - SIDS_FACT, - SIDS_RECIPROC, - SIDS_DEGREES, - SIDS_NEGATE, - SIDS_RSH, - SIDS_DIVIDEBYZERO, - SIDS_DOMAIN, - SIDS_UNDEFINED, - SIDS_POS_INFINITY, - SIDS_NEG_INFINITY, - SIDS_ABORTED, - SIDS_NOMEM, - SIDS_TOOMANY, - SIDS_OVERFLOW, - SIDS_NORESULT, - SIDS_INSUFFICIENT_DATA, - SIDS_ERR_UNK_CH, - SIDS_ERR_UNK_FN, - SIDS_ERR_UNEX_NUM, - SIDS_ERR_UNEX_CH, - SIDS_ERR_UNEX_SZ, - SIDS_ERR_MISMATCH_CLOSE, - SIDS_ERR_UNEX_END, - SIDS_ERR_SG_INV_ERROR, - SIDS_ERR_INPUT_OVERFLOW, - SIDS_ERR_OUTPUT_OVERFLOW }; +inline constexpr std::array g_sids = +{ + SIDS_PLUS_MINUS, + SIDS_C, + SIDS_CE, + SIDS_BACKSPACE, + SIDS_DECIMAL_SEPARATOR, + SIDS_EMPTY_STRING, + SIDS_AND, + SIDS_OR, + SIDS_XOR, + SIDS_LSH, + SIDS_RSH, + SIDS_DIVIDE, + SIDS_MULTIPLY, + SIDS_PLUS, + SIDS_MINUS, + SIDS_MOD, + SIDS_YROOT, + SIDS_POW_HAT, + SIDS_INT, + SIDS_ROL, + SIDS_ROR, + SIDS_NOT, + SIDS_SIN, + SIDS_COS, + SIDS_TAN, + SIDS_SINH, + SIDS_COSH, + SIDS_TANH, + SIDS_LN, + SIDS_LOG, + SIDS_SQRT, + SIDS_XPOW2, + SIDS_XPOW3, + SIDS_NFACTORIAL, + SIDS_RECIPROCAL, + SIDS_DMS, + SIDS_POWTEN, + SIDS_PERCENT, + SIDS_SCIENTIFIC_NOTATION, + SIDS_PI, + SIDS_EQUAL, + SIDS_MC, + SIDS_MR, + SIDS_MS, + SIDS_MPLUS, + SIDS_MMINUS, + SIDS_EXP, + SIDS_OPEN_PAREN, + SIDS_CLOSE_PAREN, + SIDS_0, + SIDS_1, + SIDS_2, + SIDS_3, + SIDS_4, + SIDS_5, + SIDS_6, + SIDS_7, + SIDS_8, + SIDS_9, + SIDS_A, + SIDS_B, + SIDS_C, + SIDS_D, + SIDS_E, + SIDS_F, + SIDS_FRAC, + SIDS_SIND, + SIDS_COSD, + SIDS_TAND, + SIDS_ASIND, + SIDS_ACOSD, + SIDS_ATAND, + SIDS_SINR, + SIDS_COSR, + SIDS_TANR, + SIDS_ASINR, + SIDS_ACOSR, + SIDS_ATANR, + SIDS_SING, + SIDS_COSG, + SIDS_TANG, + SIDS_ASING, + SIDS_ACOSG, + SIDS_ATANG, + SIDS_ASINH, + SIDS_ACOSH, + SIDS_ATANH, + SIDS_POWE, + SIDS_POWTEN2, + SIDS_SQRT2, + SIDS_SQR, + SIDS_CUBE, + SIDS_CUBERT, + SIDS_FACT, + SIDS_RECIPROC, + SIDS_DEGREES, + SIDS_NEGATE, + SIDS_RSH, + SIDS_DIVIDEBYZERO, + SIDS_DOMAIN, + SIDS_UNDEFINED, + SIDS_POS_INFINITY, + SIDS_NEG_INFINITY, + SIDS_ABORTED, + SIDS_NOMEM, + SIDS_TOOMANY, + SIDS_OVERFLOW, + SIDS_NORESULT, + SIDS_INSUFFICIENT_DATA, + SIDS_ERR_UNK_CH, + SIDS_ERR_UNK_FN, + SIDS_ERR_UNEX_NUM, + SIDS_ERR_UNEX_CH, + SIDS_ERR_UNEX_SZ, + SIDS_ERR_MISMATCH_CLOSE, + SIDS_ERR_UNEX_END, + SIDS_ERR_SG_INV_ERROR, + SIDS_ERR_INPUT_OVERFLOW, + SIDS_ERR_OUTPUT_OVERFLOW, + SIDS_SECD, + SIDS_SECG, + SIDS_SECR, + SIDS_ASECD, + SIDS_ASECR, + SIDS_ASECG, + SIDS_CSCD, + SIDS_CSCR, + SIDS_CSCG, + SIDS_ACSCD, + SIDS_ACSCR, + SIDS_ACSCG, + SIDS_COTD, + SIDS_COTR, + SIDS_COTG, + SIDS_ACOTD, + SIDS_ACOTR, + SIDS_ACOTG, + SIDS_SECH, + SIDS_ASECH, + SIDS_CSCH, + SIDS_ACSCH, + SIDS_COTH, + SIDS_ACOTH, + SIDS_TWOPOWX, + SIDS_LOGBASEX, + SIDS_ABS, + SIDS_FLOOR, + SIDS_CEIL, + SIDS_NAND, + SIDS_NOR, + SIDS_CUBEROOT, + SIDS_PROGRAMMER_MOD, +}; diff --git a/src/CalcManager/Header Files/History.h b/src/CalcManager/Header Files/History.h index b6d6d8db..66bac67f 100644 --- a/src/CalcManager/Header Files/History.h +++ b/src/CalcManager/Header Files/History.h @@ -21,8 +21,8 @@ public: ~CHistoryCollector(); void AddOpndToHistory(std::wstring_view numStr, CalcEngine::Rational const& rat, bool fRepetition = false); void RemoveLastOpndFromHistory(); - void AddBinOpToHistory(int nOpCode, bool fNoRepetition = true); - void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher); + void AddBinOpToHistory(int nOpCode, bool isIntgerMode, bool fNoRepetition = true); + void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode); void AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype); void AddOpenBraceToHistory(); void AddCloseBraceToHistory(); @@ -31,6 +31,7 @@ public: void EnclosePrecInversionBrackets(); bool FOpndAddedToHistory(); void CompleteHistoryLine(std::wstring_view numStr); + void CompleteEquation(std::wstring_view numStr); void ClearHistoryLine(std::wstring_view errStr); int AddCommand(_In_ const std::shared_ptr& spCommand); void UpdateHistoryExpression(uint32_t radix, int32_t precision); @@ -50,8 +51,8 @@ private: 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 wchar_t m_decimalSymbol; - std::shared_ptr>> m_spTokens; - std::shared_ptr>> m_spCommands; + std::shared_ptr>> m_spTokens; + std::shared_ptr>> m_spCommands; private: void ReinitHistory(); @@ -59,5 +60,5 @@ private: void TruncateEquationSzFromIch(int ich); void SetExpressionDisplay(); void InsertSzInEquationSz(std::wstring_view str, int icommandIndex, int ich); - std::shared_ptr> GetOperandCommandsFromString(std::wstring_view numStr); + std::shared_ptr> GetOperandCommandsFromString(std::wstring_view numStr); }; diff --git a/src/CalcManager/Header Files/ICalcDisplay.h b/src/CalcManager/Header Files/ICalcDisplay.h index f4aebec3..ee32580c 100644 --- a/src/CalcManager/Header Files/ICalcDisplay.h +++ b/src/CalcManager/Header Files/ICalcDisplay.h @@ -3,7 +3,6 @@ #pragma once -#include "../CalculatorVector.h" #include "../ExpressionCommandInterface.h" // Callback interface to be implemented by the clients of CCalcEngine @@ -13,8 +12,8 @@ public: virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) = 0; virtual void SetIsInError(bool isInError) = 0; virtual void SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands) = 0; + _Inout_ std::shared_ptr>> const& tokens, + _Inout_ std::shared_ptr>> const& commands) = 0; virtual void SetParenthesisNumber(_In_ unsigned int count) = 0; virtual void OnNoRightParenAdded() = 0; virtual void MaxDigitsReached() = 0; // not an error but still need to inform UI layer. @@ -22,4 +21,5 @@ public: virtual void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) = 0; virtual void SetMemorizedNumbers(const std::vector& memorizedNumbers) = 0; virtual void MemoryItemChanged(unsigned int indexOfMemory) = 0; + virtual void InputChanged() = 0; }; diff --git a/src/CalcManager/Header Files/IHistoryDisplay.h b/src/CalcManager/Header Files/IHistoryDisplay.h index 7e2a9019..80794ec5 100644 --- a/src/CalcManager/Header Files/IHistoryDisplay.h +++ b/src/CalcManager/Header Files/IHistoryDisplay.h @@ -1,15 +1,17 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once +#include "../ExpressionCommandInterface.h" + // Callback interface to be implemented by the clients of CCalcEngine if they require equation history class IHistoryDisplay { public: virtual ~IHistoryDisplay(){}; virtual unsigned int AddToHistory( - _In_ std::shared_ptr>> const& tokens, - _In_ std::shared_ptr>> const& commands, + _In_ std::shared_ptr>> const& tokens, + _In_ std::shared_ptr>> const& commands, _In_ std::wstring_view result) = 0; }; diff --git a/src/CalcManager/NumberFormattingUtils.cpp b/src/CalcManager/NumberFormattingUtils.cpp index 8fde3d9a..ead9013f 100644 --- a/src/CalcManager/NumberFormattingUtils.cpp +++ b/src/CalcManager/NumberFormattingUtils.cpp @@ -16,18 +16,14 @@ namespace CalcManager::NumberFormattingUtils return; } - wstring::iterator iter; - for (iter = number.end() - 1;; iter--) + if (auto i = number.find_last_not_of(L'0'); i != wstring::npos) { - if (*iter != L'0') - { - number.erase(iter + 1, number.end()); - break; - } + number.erase(number.cbegin() + i + 1, number.cend()); } - if (*(number.end() - 1) == L'.') + + if (number.back() == L'.') { - number.erase(number.end() - 1, number.end()); + number.pop_back(); } } diff --git a/src/CalcManager/Ratpack/CalcErr.h b/src/CalcManager/Ratpack/CalcErr.h index 4637c2c3..ebdc6730 100644 --- a/src/CalcManager/Ratpack/CalcErr.h +++ b/src/CalcManager/Ratpack/CalcErr.h @@ -41,45 +41,45 @@ typedef int32_t ResultCode; // CALC_E_DIVIDEBYZERO // // The current operation would require a divide by zero to complete -#define CALC_E_DIVIDEBYZERO ((uint32_t)0x80000000) +static constexpr uint32_t CALC_E_DIVIDEBYZERO = (uint32_t)0x80000000; // CALC_E_DOMAIN // // The given input is not within the domain of this function -#define CALC_E_DOMAIN ((uint32_t)0x80000001) +static constexpr uint32_t CALC_E_DOMAIN = (uint32_t)0x80000001; // CALC_E_INDEFINITE // // The result of this function is undefined -#define CALC_E_INDEFINITE ((uint32_t)0x80000002) +static constexpr uint32_t CALC_E_INDEFINITE = (uint32_t)0x80000002; // CALC_E_POSINFINITY // // The result of this function is Positive Infinity. -#define CALC_E_POSINFINITY ((uint32_t)0x80000003) +static constexpr uint32_t CALC_E_POSINFINITY = (uint32_t)0x80000003; // CALC_E_NEGINFINITY // // The result of this function is Negative Infinity -#define CALC_E_NEGINFINITY ((uint32_t)0x80000004) +static constexpr uint32_t CALC_E_NEGINFINITY = (uint32_t)0x80000004; // CALC_E_INVALIDRANGE // // The given input is within the domain of the function but is beyond // the range for which calc can successfully compute the answer -#define CALC_E_INVALIDRANGE ((uint32_t)0x80000006) +static constexpr uint32_t CALC_E_INVALIDRANGE = (uint32_t)0x80000006; // CALC_E_OUTOFMEMORY // // There is not enough free memory to complete the requested function -#define CALC_E_OUTOFMEMORY ((uint32_t)0x80000007) +static constexpr uint32_t CALC_E_OUTOFMEMORY = (uint32_t)0x80000007; // CALC_E_OVERFLOW // // The result of this operation is an overflow -#define CALC_E_OVERFLOW ((uint32_t)0x80000008) +static constexpr uint32_t CALC_E_OVERFLOW = (uint32_t)0x80000008; // CALC_E_NORESULT // // The result of this operation is undefined -#define CALC_E_NORESULT ((uint32_t)0x80000009) +static constexpr uint32_t CALC_E_NORESULT = (uint32_t)0x80000009; diff --git a/src/CalcManager/Ratpack/basex.cpp b/src/CalcManager/Ratpack/basex.cpp index 6dded335..27e6a223 100644 --- a/src/CalcManager/Ratpack/basex.cpp +++ b/src/CalcManager/Ratpack/basex.cpp @@ -34,7 +34,7 @@ void _mulnumx(PNUMBER* pa, PNUMBER b); // //---------------------------------------------------------------------------- -void mulnumx(PNUMBER* pa, PNUMBER b) +void mulnumx(_Inout_ PNUMBER* pa, _In_ PNUMBER b) { if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0) @@ -172,7 +172,7 @@ void _mulnumx(PNUMBER* pa, PNUMBER b) // //----------------------------------------------------------------------------- -void numpowi32x(_Inout_ PNUMBER* proot, _In_ int32_t power) +void numpowi32x(_Inout_ PNUMBER* proot, int32_t power) { PNUMBER lret = i32tonum(1, BASEX); @@ -215,7 +215,7 @@ void _divnumx(PNUMBER* pa, PNUMBER b, int32_t precision); // //---------------------------------------------------------------------------- -void divnumx(PNUMBER* pa, PNUMBER b, int32_t precision) +void divnumx(_Inout_ PNUMBER* pa, _In_ PNUMBER b, int32_t precision) { if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0) diff --git a/src/CalcManager/Ratpack/conv.cpp b/src/CalcManager/Ratpack/conv.cpp index d96fe306..ab7aba05 100644 --- a/src/CalcManager/Ratpack/conv.cpp +++ b/src/CalcManager/Ratpack/conv.cpp @@ -145,7 +145,7 @@ void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER* const src) // //----------------------------------------------------------------------------- -void _destroynum(_In_ PNUMBER pnum) +void _destroynum(_Frees_ptr_opt_ PNUMBER pnum) { if (pnum != nullptr) @@ -167,7 +167,7 @@ void _destroynum(_In_ PNUMBER pnum) // //----------------------------------------------------------------------------- -void _destroyrat(_In_ PRAT prat) +void _destroyrat(_Frees_ptr_opt_ PRAT prat) { if (prat != nullptr) @@ -741,8 +741,10 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis destroynum(pnumret); pnumret = nullptr; } - - stripzeroesnum(pnumret, precision); + else + { + stripzeroesnum(pnumret, precision); + } return pnumret; } @@ -760,7 +762,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis // //----------------------------------------------------------------------------- -PRAT i32torat(_In_ int32_t ini32) +PRAT i32torat(int32_t ini32) { PRAT pratret = nullptr; @@ -784,7 +786,7 @@ PRAT i32torat(_In_ int32_t ini32) // //----------------------------------------------------------------------------- -PRAT Ui32torat(_In_ uint32_t inui32) +PRAT Ui32torat(uint32_t inui32) { PRAT pratret = nullptr; @@ -1202,78 +1204,73 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_ } // Begin building the result string - wstringstream resultStream{}; + wstring result; // Make sure negative zeros aren't allowed. if ((pnum->sign == -1) && (length > 0)) { - resultStream << L'-'; + result = L'-'; } if (exponent <= 0 && !useSciForm) { - resultStream << L'0'; - resultStream << g_decimalSeparator; + result += L'0'; + result += g_decimalSeparator; // Used up a digit unaccounted for. } while (exponent < 0) { - resultStream << L'0'; + result += L'0'; exponent++; } while (length > 0) { exponent--; - resultStream << DIGITS[*pmant--]; + result += DIGITS[*pmant--]; length--; // Be more regular in using a decimal point. if (exponent == 0) { - resultStream << g_decimalSeparator; + result += g_decimalSeparator; } } while (exponent > 0) { - resultStream << L'0'; + result += L'0'; exponent--; // Be more regular in using a decimal point. if (exponent == 0) { - resultStream << g_decimalSeparator; + result += g_decimalSeparator; } } if (useSciForm) { - resultStream << (radix == 10 ? L'e' : L'^'); - resultStream << (eout < 0 ? L'-' : L'+'); + result += (radix == 10 ? L'e' : L'^'); + result += (eout < 0 ? L'-' : L'+'); eout = abs(eout); - wstringstream exponentStream{}; + wstring expString{}; do { - exponentStream << DIGITS[eout % radix]; + expString += DIGITS[eout % radix]; eout /= radix; } while (eout > 0); - auto expString = exponentStream.str(); - for (auto ritr = expString.rbegin(); ritr != expString.rend(); ritr++) - { - resultStream << *ritr; - } + result.insert(result.end(), expString.crbegin(), expString.crend()); } // Remove trailing decimal - auto resultString = resultStream.str(); - if (!resultString.empty() && resultString.back() == g_decimalSeparator) + if (!result.empty() && result.back() == g_decimalSeparator) { - resultString.pop_back(); + result.pop_back(); } - return resultString; + return result; } //----------------------------------------------------------------------------- diff --git a/src/CalcManager/Ratpack/exp.cpp b/src/CalcManager/Ratpack/exp.cpp index 1252002d..23257f73 100644 --- a/src/CalcManager/Ratpack/exp.cpp +++ b/src/CalcManager/Ratpack/exp.cpp @@ -39,7 +39,7 @@ // //----------------------------------------------------------------------------- -void _exprat(PRAT* px, int32_t precision) +void _exprat(_Inout_ PRAT* px, int32_t precision) { CREATETAYLOR(); @@ -58,7 +58,7 @@ void _exprat(PRAT* px, int32_t precision) DESTROYTAYLOR(); } -void exprat(PRAT* px, uint32_t radix, int32_t precision) +void exprat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT pwr = nullptr; @@ -150,7 +150,7 @@ void _lograt(PRAT* px, int32_t precision) DESTROYTAYLOR(); } -void lograt(PRAT* px, int32_t precision) +void lograt(_Inout_ PRAT* px, int32_t precision) { bool fneglog; @@ -224,7 +224,7 @@ void lograt(PRAT* px, int32_t precision) destroyrat(pwr); } -void log10rat(PRAT* px, int32_t precision) +void log10rat(_Inout_ PRAT* px, int32_t precision) { lograt(px, precision); @@ -267,7 +267,7 @@ bool IsEven(PRAT x, uint32_t radix, int32_t precision) // // //--------------------------------------------------------------------------- -void powrat(PRAT* px, PRAT y, uint32_t radix, int32_t precision) +void powrat(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision) { // Handle cases where px or y is 0 by calling powratcomp directly if (zerrat(*px) || zerrat(y)) @@ -294,7 +294,7 @@ void powrat(PRAT* px, PRAT y, uint32_t radix, int32_t precision) } } -void powratNumeratorDenominator(PRAT* px, PRAT y, uint32_t radix, int32_t precision) +void powratNumeratorDenominator(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision) { // Prepare rationals PRAT yNumerator = nullptr; @@ -403,7 +403,7 @@ void powratNumeratorDenominator(PRAT* px, PRAT y, uint32_t radix, int32_t precis // // //--------------------------------------------------------------------------- -void powratcomp(PRAT* px, PRAT y, uint32_t radix, int32_t precision) +void powratcomp(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision) { int32_t sign = SIGN(*px); diff --git a/src/CalcManager/Ratpack/fact.cpp b/src/CalcManager/Ratpack/fact.cpp index 4bb2a71a..c026e536 100644 --- a/src/CalcManager/Ratpack/fact.cpp +++ b/src/CalcManager/Ratpack/fact.cpp @@ -190,7 +190,7 @@ void _gamma(PRAT* pn, uint32_t radix, int32_t precision) destroyrat(sum); } -void factrat(PRAT* px, uint32_t radix, int32_t precision) +void factrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT fact = nullptr; diff --git a/src/CalcManager/Ratpack/itrans.cpp b/src/CalcManager/Ratpack/itrans.cpp index 18c1fb41..9bb94358 100644 --- a/src/CalcManager/Ratpack/itrans.cpp +++ b/src/CalcManager/Ratpack/itrans.cpp @@ -83,7 +83,7 @@ void asinanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_ ascalerat(pa, angletype, precision); } -void asinrat(PRAT* px, uint32_t radix, int32_t precision) +void asinrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT pret = nullptr; @@ -190,7 +190,7 @@ void _acosrat(PRAT* px, int32_t precision) DESTROYTAYLOR(); } -void acosrat(PRAT* px, uint32_t radix, int32_t precision) +void acosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { int32_t sgn = SIGN(*px); @@ -276,7 +276,7 @@ void _atanrat(PRAT* px, int32_t precision) DESTROYTAYLOR(); } -void atanrat(PRAT* px, uint32_t radix, int32_t precision) +void atanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT tmpx = nullptr; diff --git a/src/CalcManager/Ratpack/itransh.cpp b/src/CalcManager/Ratpack/itransh.cpp index d1ec113f..36c3c48f 100644 --- a/src/CalcManager/Ratpack/itransh.cpp +++ b/src/CalcManager/Ratpack/itransh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. //----------------------------------------------------------------------------- @@ -47,7 +47,7 @@ // //----------------------------------------------------------------------------- -void asinhrat(PRAT* px, uint32_t radix, int32_t precision) +void asinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT neg_pt_eight_five = nullptr; @@ -101,7 +101,7 @@ void asinhrat(PRAT* px, uint32_t radix, int32_t precision) // //----------------------------------------------------------------------------- -void acoshrat(PRAT* px, uint32_t radix, int32_t precision) +void acoshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { if (rat_lt(*px, rat_one, precision)) @@ -138,7 +138,7 @@ void acoshrat(PRAT* px, uint32_t radix, int32_t precision) // //----------------------------------------------------------------------------- -void atanhrat(PRAT* px, int32_t precision) +void atanhrat(_Inout_ PRAT* px, int32_t precision) { PRAT ptmp = nullptr; diff --git a/src/CalcManager/Ratpack/logic.cpp b/src/CalcManager/Ratpack/logic.cpp index b3970ef4..c9094f33 100644 --- a/src/CalcManager/Ratpack/logic.cpp +++ b/src/CalcManager/Ratpack/logic.cpp @@ -17,7 +17,7 @@ using namespace std; -void lshrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision) +void lshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision) { PRAT pwr = nullptr; @@ -40,7 +40,7 @@ void lshrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision) } } -void rshrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision) +void rshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision) { PRAT pwr = nullptr; @@ -73,19 +73,19 @@ enum FUNC_XOR } BOOL_FUNCS; -void andrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision) +void andrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision) { boolrat(pa, b, FUNC_AND, radix, precision); } -void orrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision) +void orrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision) { boolrat(pa, b, FUNC_OR, radix, precision); } -void xorrat(PRAT* pa, PRAT b, uint32_t radix, int32_t precision) +void xorrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision) { boolrat(pa, b, FUNC_XOR, radix, precision); @@ -191,7 +191,7 @@ void boolnum(PNUMBER* pa, PNUMBER b, int func) // //----------------------------------------------------------------------------- -void remrat(PRAT* pa, PRAT b) +void remrat(_Inout_ PRAT* pa, _In_ PRAT b) { if (zerrat(b)) @@ -228,7 +228,7 @@ void remrat(PRAT* pa, PRAT b) // //----------------------------------------------------------------------------- -void modrat(PRAT* pa, PRAT b) +void modrat(_Inout_ PRAT* pa, _In_ PRAT b) { // contrary to remrat(X, 0) returning 0, modrat(X, 0) must return X if (zerrat(b)) diff --git a/src/CalcManager/Ratpack/num.cpp b/src/CalcManager/Ratpack/num.cpp index 773f0b7d..c4561052 100644 --- a/src/CalcManager/Ratpack/num.cpp +++ b/src/CalcManager/Ratpack/num.cpp @@ -43,7 +43,7 @@ using namespace std; void _addnum(PNUMBER* pa, PNUMBER b, uint32_t radix); -void addnum(PNUMBER* pa, PNUMBER b, uint32_t radix) +void addnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix) { if (b->cdigit > 1 || b->mant[0] != 0) @@ -186,7 +186,7 @@ void _addnum(PNUMBER* pa, PNUMBER b, uint32_t radix) void _mulnum(PNUMBER* pa, PNUMBER b, uint32_t radix); -void mulnum(PNUMBER* pa, PNUMBER b, uint32_t radix) +void mulnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix) { if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0) @@ -302,7 +302,7 @@ void _mulnum(PNUMBER* pa, PNUMBER b, uint32_t radix) // //---------------------------------------------------------------------------- -void remnum(PNUMBER* pa, PNUMBER b, uint32_t radix) +void remnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix) { PNUMBER tmp = nullptr; // tmp is the working remainder. @@ -365,7 +365,7 @@ void remnum(PNUMBER* pa, PNUMBER b, uint32_t radix) void _divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision); -void divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision) +void divnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix, int32_t precision) { if (b->cdigit > 1 || b->mant[0] != 1 || b->exp != 0) @@ -489,7 +489,7 @@ void _divnum(PNUMBER* pa, PNUMBER b, uint32_t radix, int32_t precision) // //--------------------------------------------------------------------------- -bool equnum(PNUMBER a, PNUMBER b) +bool equnum(_In_ PNUMBER a, _In_ PNUMBER b) { int32_t diff; @@ -555,7 +555,7 @@ bool equnum(PNUMBER a, PNUMBER b) // //--------------------------------------------------------------------------- -bool lessnum(PNUMBER a, PNUMBER b) +bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b) { int32_t diff; @@ -614,7 +614,7 @@ bool lessnum(PNUMBER a, PNUMBER b) // //---------------------------------------------------------------------------- -bool zernum(PNUMBER a) +bool zernum(_In_ PNUMBER a) { int32_t length; diff --git a/src/CalcManager/Ratpack/rat.cpp b/src/CalcManager/Ratpack/rat.cpp index 4315add1..c0566038 100644 --- a/src/CalcManager/Ratpack/rat.cpp +++ b/src/CalcManager/Ratpack/rat.cpp @@ -37,7 +37,7 @@ using namespace std; // //----------------------------------------------------------------------------- -void gcdrat(PRAT* pa, int32_t precision) +void gcdrat(_Inout_ PRAT* pa, int32_t precision) { PNUMBER pgcd = nullptr; @@ -70,7 +70,7 @@ void gcdrat(PRAT* pa, int32_t precision) // //----------------------------------------------------------------------------- -void fracrat(PRAT* pa, uint32_t radix, int32_t precision) +void fracrat(_Inout_ PRAT* pa, uint32_t radix, int32_t precision) { // Only do the flatrat operation if number is nonzero. // and only if the bottom part is not one. @@ -98,7 +98,7 @@ void fracrat(PRAT* pa, uint32_t radix, int32_t precision) // //----------------------------------------------------------------------------- -void mulrat(PRAT* pa, PRAT b, int32_t precision) +void mulrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision) { // Only do the multiply if it isn't zero. @@ -132,7 +132,7 @@ void mulrat(PRAT* pa, PRAT b, int32_t precision) // //----------------------------------------------------------------------------- -void divrat(PRAT* pa, PRAT b, int32_t precision) +void divrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision) { if (!zernum((*pa)->pp)) @@ -182,7 +182,7 @@ void divrat(PRAT* pa, PRAT b, int32_t precision) // //----------------------------------------------------------------------------- -void subrat(PRAT* pa, PRAT b, int32_t precision) +void subrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision) { b->pp->sign *= -1; @@ -203,7 +203,7 @@ void subrat(PRAT* pa, PRAT b, int32_t precision) // //----------------------------------------------------------------------------- -void addrat(PRAT* pa, PRAT b, int32_t precision) +void addrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision) { PNUMBER bot = nullptr; @@ -255,7 +255,7 @@ void addrat(PRAT* pa, PRAT b, int32_t precision) // //----------------------------------------------------------------------------- -void rootrat(PRAT* py, PRAT n, uint32_t radix, int32_t precision) +void rootrat(_Inout_ PRAT* py, _In_ PRAT n, uint32_t radix, int32_t precision) { // Initialize 1/n PRAT oneovern = nullptr; @@ -280,7 +280,7 @@ void rootrat(PRAT* py, PRAT n, uint32_t radix, int32_t precision) // //----------------------------------------------------------------------------- -bool zerrat(PRAT a) +bool zerrat(_In_ PRAT a) { return (zernum(a->pp)); diff --git a/src/CalcManager/Ratpack/ratpak.h b/src/CalcManager/Ratpack/ratpak.h index dc6a98d9..18b2d024 100644 --- a/src/CalcManager/Ratpack/ratpak.h +++ b/src/CalcManager/Ratpack/ratpak.h @@ -369,7 +369,7 @@ extern PNUMBER i32factnum(int32_t ini32, uint32_t radix); extern PNUMBER i32prodnum(int32_t start, int32_t stop, uint32_t radix); extern PNUMBER i32tonum(int32_t ini32, uint32_t radix); extern PNUMBER Ui32tonum(uint32_t ini32, uint32_t radix); -extern PNUMBER numtonRadixx(PNUMBER a, uint32_t radix); +extern PNUMBER numtonRadixx(_In_ PNUMBER a, uint32_t radix); // creates a empty/undefined rational representation (p/q) extern PRAT _createrat(void); @@ -446,8 +446,8 @@ extern void tananglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, extern void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER* const src); -extern void _destroynum(_In_ PNUMBER pnum); -extern void _destroyrat(_In_ PRAT prat); +extern void _destroynum(_Frees_ptr_opt_ PNUMBER pnum); +extern void _destroyrat(_Frees_ptr_opt_ PRAT prat); extern void addnum(_Inout_ PNUMBER* pa, _In_ PNUMBER b, uint32_t radix); extern void addrat(_Inout_ PRAT* pa, _In_ PRAT b, int32_t precision); extern void andrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision); diff --git a/src/CalcManager/Ratpack/support.cpp b/src/CalcManager/Ratpack/support.cpp index a46b180c..81c737f5 100644 --- a/src/CalcManager/Ratpack/support.cpp +++ b/src/CalcManager/Ratpack/support.cpp @@ -296,7 +296,7 @@ void ChangeConstants(uint32_t radix, int32_t precision) // //---------------------------------------------------------------------------- -void intrat(PRAT* px, uint32_t radix, int32_t precision) +void intrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { // Only do the intrat operation if number is nonzero. // and only if the bottom part is not one. @@ -328,7 +328,7 @@ void intrat(PRAT* px, uint32_t radix, int32_t precision) // //--------------------------------------------------------------------------- -bool rat_equ(PRAT a, PRAT b, int32_t precision) +bool rat_equ(_In_ PRAT a, _In_ PRAT b, int32_t precision) { PRAT rattmp = nullptr; @@ -351,7 +351,7 @@ bool rat_equ(PRAT a, PRAT b, int32_t precision) // //--------------------------------------------------------------------------- -bool rat_ge(PRAT a, PRAT b, int32_t precision) +bool rat_ge(_In_ PRAT a, _In_ PRAT b, int32_t precision) { PRAT rattmp = nullptr; @@ -375,7 +375,7 @@ bool rat_ge(PRAT a, PRAT b, int32_t precision) // //--------------------------------------------------------------------------- -bool rat_gt(PRAT a, PRAT b, int32_t precision) +bool rat_gt(_In_ PRAT a, _In_ PRAT b, int32_t precision) { PRAT rattmp = nullptr; @@ -399,7 +399,7 @@ bool rat_gt(PRAT a, PRAT b, int32_t precision) // //--------------------------------------------------------------------------- -bool rat_le(PRAT a, PRAT b, int32_t precision) +bool rat_le(_In_ PRAT a, _In_ PRAT b, int32_t precision) { PRAT rattmp = nullptr; @@ -423,7 +423,7 @@ bool rat_le(PRAT a, PRAT b, int32_t precision) // //--------------------------------------------------------------------------- -bool rat_lt(PRAT a, PRAT b, int32_t precision) +bool rat_lt(_In_ PRAT a, _In_ PRAT b, int32_t precision) { PRAT rattmp = nullptr; @@ -447,7 +447,7 @@ bool rat_lt(PRAT a, PRAT b, int32_t precision) // //--------------------------------------------------------------------------- -bool rat_neq(PRAT a, PRAT b, int32_t precision) +bool rat_neq(_In_ PRAT a, _In_ PRAT b, int32_t precision) { PRAT rattmp = nullptr; @@ -470,7 +470,7 @@ bool rat_neq(PRAT a, PRAT b, int32_t precision) // //--------------------------------------------------------------------------- -void scale(PRAT* px, PRAT scalefact, uint32_t radix, int32_t precision) +void scale(_Inout_ PRAT* px, _In_ PRAT scalefact, uint32_t radix, int32_t precision) { PRAT pret = nullptr; DUPRAT(pret, *px); @@ -503,7 +503,7 @@ void scale(PRAT* px, PRAT scalefact, uint32_t radix, int32_t precision) // //--------------------------------------------------------------------------- -void scale2pi(PRAT* px, uint32_t radix, int32_t precision) +void scale2pi(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT pret = nullptr; PRAT my_two_pi = nullptr; @@ -546,7 +546,7 @@ void scale2pi(PRAT* px, uint32_t radix, int32_t precision) // //--------------------------------------------------------------------------- -void inbetween(PRAT* px, PRAT range, int32_t precision) +void inbetween(_In_ PRAT* px, _In_ PRAT range, int32_t precision) { if (rat_gt(*px, range, precision)) @@ -575,7 +575,7 @@ void inbetween(PRAT* px, PRAT range, int32_t precision) // //--------------------------------------------------------------------------- -void _dumprawrat(const wchar_t* varname, PRAT rat, wostream& out) +void _dumprawrat(_In_ const wchar_t* varname, _In_ PRAT rat, wostream& out) { _dumprawnum(varname, rat->pp, out); @@ -593,7 +593,7 @@ void _dumprawrat(const wchar_t* varname, PRAT rat, wostream& out) // //--------------------------------------------------------------------------- -void _dumprawnum(const wchar_t* varname, PNUMBER num, wostream& out) +void _dumprawnum(_In_ const wchar_t* varname, _In_ PNUMBER num, wostream& out) { int i; @@ -676,7 +676,7 @@ void _readconstants(void) // //--------------------------------------------------------------------------- -void trimit(PRAT* px, int32_t precision) +void trimit(_Inout_ PRAT* px, int32_t precision) { if (!g_ftrueinfinite) diff --git a/src/CalcManager/Ratpack/trans.cpp b/src/CalcManager/Ratpack/trans.cpp index 30104abb..e848155d 100644 --- a/src/CalcManager/Ratpack/trans.cpp +++ b/src/CalcManager/Ratpack/trans.cpp @@ -187,7 +187,7 @@ void _cosrat(PRAT* px, uint32_t radix, int32_t precision) } } -void cosrat(PRAT* px, uint32_t radix, int32_t precision) +void cosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { scale2pi(px, radix, precision); _cosrat(px, radix, precision); @@ -257,7 +257,7 @@ void _tanrat(PRAT* px, uint32_t radix, int32_t precision) destroyrat(ptmp); } -void tanrat(PRAT* px, uint32_t radix, int32_t precision) +void tanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { scale2pi(px, radix, precision); _tanrat(px, radix, precision); diff --git a/src/CalcManager/Ratpack/transh.cpp b/src/CalcManager/Ratpack/transh.cpp index 006db769..8e033aa5 100644 --- a/src/CalcManager/Ratpack/transh.cpp +++ b/src/CalcManager/Ratpack/transh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. //----------------------------------------------------------------------------- @@ -88,7 +88,7 @@ void _sinhrat(PRAT* px, int32_t precision) DESTROYTAYLOR(); } -void sinhrat(PRAT* px, uint32_t radix, int32_t precision) +void sinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT tmpx = nullptr; @@ -169,7 +169,7 @@ void _coshrat(PRAT* px, uint32_t radix, int32_t precision) DESTROYTAYLOR(); } -void coshrat(PRAT* px, uint32_t radix, int32_t precision) +void coshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT tmpx = nullptr; @@ -211,7 +211,7 @@ void coshrat(PRAT* px, uint32_t radix, int32_t precision) // //----------------------------------------------------------------------------- -void tanhrat(PRAT* px, uint32_t radix, int32_t precision) +void tanhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision) { PRAT ptmp = nullptr; diff --git a/src/CalcManager/UnitConverter.cpp b/src/CalcManager/UnitConverter.cpp index eb361fa5..ce0ebb81 100644 --- a/src/CalcManager/UnitConverter.cpp +++ b/src/CalcManager/UnitConverter.cpp @@ -109,11 +109,10 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i { if (m_currentCategory.id != input.id) { - vector& unitVector = m_categoryToUnits[m_currentCategory]; - for (unsigned int i = 0; i < unitVector.size(); i++) + for (auto& unit : m_categoryToUnits[m_currentCategory]) { - unitVector[i].isConversionSource = (unitVector[i].id == m_fromType.id); - unitVector[i].isConversionTarget = (unitVector[i].id == m_toType.id); + unit.isConversionSource = (unit.id == m_fromType.id); + unit.isConversionTarget = (unit.id == m_toType.id); } m_currentCategory = input; if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-') @@ -192,41 +191,51 @@ void UnitConverter::SwitchActive(const wstring& newValue) } } -wstring UnitConverter::CategoryToString(const Category& c, const wchar_t* delimiter) +wstring UnitConverter::CategoryToString(const Category& c, wstring_view delimiter) { - wstringstream out(wstringstream::out); - out << Quote(std::to_wstring(c.id)) << delimiter << Quote(std::to_wstring(c.supportsNegative)) << delimiter << Quote(c.name) << delimiter; - return out.str(); + return Quote(std::to_wstring(c.id)) + .append(delimiter) + .append(Quote(std::to_wstring(c.supportsNegative))) + .append(delimiter) + .append(Quote(c.name)) + .append(delimiter); } -vector UnitConverter::StringToVector(const wstring& w, const wchar_t* delimiter, bool addRemainder) +vector UnitConverter::StringToVector(wstring_view w, wstring_view delimiter, bool addRemainder) { size_t delimiterIndex = w.find(delimiter); size_t startIndex = 0; - vector serializedTokens = vector(); - while (delimiterIndex != wstring::npos) + vector serializedTokens; + while (delimiterIndex != wstring_view::npos) { - serializedTokens.push_back(w.substr(startIndex, delimiterIndex - startIndex)); - startIndex = delimiterIndex + (int)wcslen(delimiter); + serializedTokens.emplace_back(w.substr(startIndex, delimiterIndex - startIndex)); + startIndex = delimiterIndex + (int)delimiter.size(); delimiterIndex = w.find(delimiter, startIndex); } if (addRemainder) { delimiterIndex = w.size(); - serializedTokens.push_back(w.substr(startIndex, delimiterIndex - startIndex)); + serializedTokens.emplace_back(w.substr(startIndex, delimiterIndex - startIndex)); } return serializedTokens; } -wstring UnitConverter::UnitToString(const Unit& u, const wchar_t* delimiter) +wstring UnitConverter::UnitToString(const Unit& u, wstring_view delimiter) { - wstringstream out(wstringstream::out); - out << Quote(std::to_wstring(u.id)) << delimiter << Quote(u.name) << delimiter << Quote(u.abbreviation) << delimiter - << std::to_wstring(u.isConversionSource) << delimiter << std::to_wstring(u.isConversionTarget) << delimiter << std::to_wstring(u.isWhimsical) - << delimiter; - return out.str(); + return Quote(std::to_wstring(u.id)) + .append(delimiter) + .append(Quote(u.name)) + .append(delimiter) + .append(Quote(u.abbreviation)) + .append(delimiter) + .append(std::to_wstring(u.isConversionSource)) + .append(delimiter) + .append(std::to_wstring(u.isConversionTarget)) + .append(delimiter) + .append(std::to_wstring(u.isWhimsical)) + .append(delimiter); } -Unit UnitConverter::StringToUnit(const wstring& w) +Unit UnitConverter::StringToUnit(wstring_view w) { vector tokenList = StringToVector(w, L";"); assert(tokenList.size() == EXPECTEDSERIALIZEDUNITTOKENCOUNT); @@ -241,7 +250,7 @@ Unit UnitConverter::StringToUnit(const wstring& w) return serializedUnit; } -Category UnitConverter::StringToCategory(const wstring& w) +Category UnitConverter::StringToCategory(wstring_view w) { vector tokenList = StringToVector(w, L";"); assert(tokenList.size() == EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT); @@ -255,8 +264,8 @@ Category UnitConverter::StringToCategory(const wstring& w) /// /// De-Serializes the data in the converter from a string /// -/// wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it -void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) +/// wstring_view holding the serialized data. If it does not have expected number of parameters, we will ignore it +void UnitConverter::RestoreUserPreferences(wstring_view userPreferences) { if (userPreferences.empty()) { @@ -294,58 +303,57 @@ void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) /// wstring UnitConverter::SaveUserPreferences() { - wstringstream out(wstringstream::out); - const wchar_t* delimiter = L";"; - - out << UnitToString(m_fromType, delimiter) << "|"; - out << UnitToString(m_toType, delimiter) << "|"; - out << CategoryToString(m_currentCategory, delimiter) << "|"; - wstring test = out.str(); - return test; + constexpr auto delimiter = L";"sv; + constexpr auto pipe = L"|"sv; + return UnitToString(m_fromType, delimiter) + .append(pipe) + .append(UnitToString(m_toType, delimiter)) + .append(pipe) + .append(CategoryToString(m_currentCategory, delimiter)) + .append(pipe); } /// /// Sanitizes the input string, escape quoting any symbols we rely on for our delimiters, and returns the sanitized string. /// -/// wstring to be sanitized -wstring UnitConverter::Quote(const wstring& s) +/// wstring_view to be sanitized +wstring UnitConverter::Quote(wstring_view s) { - wstringstream quotedString(wstringstream::out); + wstring quotedString; // Iterate over the delimiter characters we need to quote - wstring::const_iterator cursor = s.begin(); - while (cursor != s.end()) + for (const auto ch : s) { - if (quoteConversions.find(*cursor) != quoteConversions.end()) + if (quoteConversions.find(ch) != quoteConversions.end()) { - quotedString << quoteConversions[*cursor]; + quotedString += quoteConversions[ch]; } else { - quotedString << *cursor; + quotedString += ch; } - ++cursor; } - return quotedString.str(); + + return quotedString; } /// /// Unsanitizes the sanitized input string, returning it to its original contents before we had quoted it. /// -/// wstring to be unsanitized -wstring UnitConverter::Unquote(const wstring& s) +/// wstring_view to be unsanitized +wstring UnitConverter::Unquote(wstring_view s) { - wstringstream quotedSubString(wstringstream::out); - wstringstream unquotedString(wstringstream::out); - wstring::const_iterator cursor = s.begin(); + wstring quotedSubString; + wstring unquotedString; + wstring_view::const_iterator cursor = s.begin(); while (cursor != s.end()) { if (*cursor == LEFTESCAPECHAR) { - quotedSubString.str(L""); + quotedSubString.clear(); while (cursor != s.end() && *cursor != RIGHTESCAPECHAR) { - quotedSubString << *cursor; + quotedSubString += *cursor; ++cursor; } if (cursor == s.end()) @@ -355,17 +363,17 @@ wstring UnitConverter::Unquote(const wstring& s) } else { - quotedSubString << *cursor; - unquotedString << unquoteConversions[quotedSubString.str()]; + quotedSubString += *cursor; + unquotedString += unquoteConversions[quotedSubString]; } } else { - unquotedString << *cursor; + unquotedString += *cursor; } ++cursor; } - return unquotedString.str(); + return unquotedString; } /// @@ -381,16 +389,7 @@ void UnitConverter::SendCommand(Command command) // 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(); @@ -398,46 +397,54 @@ void UnitConverter::SendCommand(Command command) clearFront = true; clearBack = false; } + else + { + clearFront = (m_currentDisplay == L"0"); + clearBack = + ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED) + || (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED)); + } + switch (command) { case Command::Zero: - m_currentDisplay += L"0"; + m_currentDisplay += L'0'; break; case Command::One: - m_currentDisplay += L"1"; + m_currentDisplay += L'1'; break; case Command::Two: - m_currentDisplay += L"2"; + m_currentDisplay += L'2'; break; case Command::Three: - m_currentDisplay += L"3"; + m_currentDisplay += L'3'; break; case Command::Four: - m_currentDisplay += L"4"; + m_currentDisplay += L'4'; break; case Command::Five: - m_currentDisplay += L"5"; + m_currentDisplay += L'5'; break; case Command::Six: - m_currentDisplay += L"6"; + m_currentDisplay += L'6'; break; case Command::Seven: - m_currentDisplay += L"7"; + m_currentDisplay += L'7'; break; case Command::Eight: - m_currentDisplay += L"8"; + m_currentDisplay += L'8'; break; case Command::Nine: - m_currentDisplay += L"9"; + m_currentDisplay += L'9'; break; case Command::Decimal: @@ -445,7 +452,7 @@ void UnitConverter::SendCommand(Command command) clearBack = false; if (!m_currentHasDecimal) { - m_currentDisplay += L"."; + m_currentDisplay += L'.'; m_currentHasDecimal = true; } break; @@ -453,9 +460,9 @@ void UnitConverter::SendCommand(Command command) case Command::Backspace: clearFront = false; clearBack = false; - if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) + if ((m_currentDisplay.front() != L'-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) { - if (m_currentDisplay.back() == '.') + if (m_currentDisplay.back() == L'.') { m_currentHasDecimal = false; } @@ -473,13 +480,13 @@ void UnitConverter::SendCommand(Command command) clearBack = false; if (m_currentCategory.supportsNegative) { - if (m_currentDisplay.front() == '-') + if (m_currentDisplay.front() == L'-') { m_currentDisplay.erase(0, 1); } else { - m_currentDisplay.insert(0, 1, '-'); + m_currentDisplay.insert(0, 1, L'-'); } } break; @@ -507,7 +514,7 @@ void UnitConverter::SendCommand(Command command) } if (clearBack) { - m_currentDisplay.erase(m_currentDisplay.size() - 1, 1); + m_currentDisplay.pop_back(); m_vmCallback->MaxDigitsReached(); } @@ -555,7 +562,7 @@ future> UnitConverter::RefreshCurrencyRatios() return async([this, currencyDataLoader, sharedLoadResult]() { sharedLoadResult.wait(); bool didLoad = sharedLoadResult.get(); - wstring timestamp = L""; + wstring timestamp; if (currencyDataLoader != nullptr) { timestamp = currencyDataLoader->GetCurrencyTimestamp(); @@ -571,11 +578,11 @@ shared_ptr UnitConverter::GetCurrencyConverterData } /// -/// Converts a double value into another unit type, currently by multiplying by the given double ratio +/// Converts a double value into another unit type /// /// double input value to convert -/// double conversion ratio to use -double UnitConverter::Convert(double value, ConversionData conversionData) +/// offset and ratio to use +double UnitConverter::Convert(double value, const ConversionData& conversionData) { if (conversionData.offsetFirst) { @@ -649,7 +656,7 @@ vector> UnitConverter::CalculateSuggested() if (stod(roundedString) != 0.0 || m_currentCategory.supportsNegative) { TrimTrailingZeros(roundedString); - returnVector.push_back(make_tuple(roundedString, entry.type)); + returnVector.emplace_back(roundedString, entry.type); } } @@ -689,13 +696,13 @@ vector> UnitConverter::CalculateSuggested() if (stod(roundedString) != 0.0) { TrimTrailingZeros(roundedString); - whimsicalReturnVector.push_back(make_tuple(roundedString, entry.type)); + whimsicalReturnVector.emplace_back(roundedString, entry.type); } } // Pickup the 'best' whimsical value - currently the first one - if (whimsicalReturnVector.size() != 0) + if (!whimsicalReturnVector.empty()) { - returnVector.push_back(whimsicalReturnVector.at(0)); + returnVector.push_back(whimsicalReturnVector.front()); } return returnVector; @@ -738,7 +745,7 @@ void UnitConverter::ResetCategoriesAndRatios() // we just want to make sure we don't let an unready category be the default. if (!units.empty()) { - for (Unit u : units) + for (const Unit& u : units) { m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u); } @@ -788,7 +795,7 @@ void UnitConverter::InitializeSelectedUnits() return; } - vector curUnits = itr->second; + const vector& curUnits = itr->second; if (!curUnits.empty()) { // Units may already have been initialized through UnitConverter::RestoreUserPreferences(). @@ -896,8 +903,8 @@ void UnitConverter::Calculate() } else { - // Fewer digits are needed following the decimal if the number is large, - // we calculate the number of decimals necessary based on the number of digits in the integer part. + // Fewer digits are needed following the decimal if the number is large, + // we calculate the number of decimals necessary based on the number of digits in the integer part. precision = max(0, max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits)) - numPreDecimal); } diff --git a/src/CalcManager/UnitConverter.h b/src/CalcManager/UnitConverter.h index 27b8629d..9d65324e 100644 --- a/src/CalcManager/UnitConverter.h +++ b/src/CalcManager/UnitConverter.h @@ -50,10 +50,6 @@ namespace UnitConversionManager accessibleName = nameValue1 + L" " + nameValue2; } - virtual ~Unit() - { - } - int id; std::wstring name; std::wstring accessibleName; @@ -145,10 +141,6 @@ namespace UnitConversionManager { } - virtual ~ConversionData() - { - } - double ratio; double offset; bool offsetFirst; @@ -238,7 +230,7 @@ namespace UnitConversionManager virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0; virtual void SwitchActive(const std::wstring& newValue) = 0; virtual std::wstring SaveUserPreferences() = 0; - virtual void RestoreUserPreferences(_In_ const std::wstring& userPreferences) = 0; + virtual void RestoreUserPreferences(_In_ std::wstring_view userPreferences) = 0; virtual void SendCommand(Command command) = 0; virtual void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) = 0; virtual void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) = 0; @@ -261,7 +253,7 @@ namespace UnitConversionManager void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override; void SwitchActive(const std::wstring& newValue) override; std::wstring SaveUserPreferences() override; - void RestoreUserPreferences(const std::wstring& userPreference) override; + void RestoreUserPreferences(std::wstring_view userPreference) override; void SendCommand(Command command) override; void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) override; void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) override; @@ -270,20 +262,20 @@ namespace UnitConversionManager void ResetCategoriesAndRatios() override; // IUnitConverter - static std::vector StringToVector(const std::wstring& w, const wchar_t* delimiter, bool addRemainder = false); - static std::wstring Quote(const std::wstring& s); - static std::wstring Unquote(const std::wstring& s); + static std::vector StringToVector(std::wstring_view w, std::wstring_view delimiter, bool addRemainder = false); + static std::wstring Quote(std::wstring_view s); + static std::wstring Unquote(std::wstring_view s); private: bool CheckLoad(); - double Convert(double value, ConversionData conversionData); + double Convert(double value, const ConversionData& conversionData); std::vector> CalculateSuggested(); void ClearValues(); void InitializeSelectedUnits(); - Category StringToCategory(const std::wstring& w); - std::wstring CategoryToString(const Category& c, const wchar_t* delimiter); - std::wstring UnitToString(const Unit& u, const wchar_t* delimiter); - Unit StringToUnit(const std::wstring& w); + Category StringToCategory(std::wstring_view w); + std::wstring CategoryToString(const Category& c, std::wstring_view delimiter); + std::wstring UnitToString(const Unit& u, std::wstring_view delimiter); + Unit StringToUnit(std::wstring_view w); void UpdateCurrencySymbols(); void UpdateViewModel(); bool AnyUnitIsEmpty(); diff --git a/src/CalcManager/pch.h b/src/CalcManager/pch.h index 9207ebff..288bbc91 100644 --- a/src/CalcManager/pch.h +++ b/src/CalcManager/pch.h @@ -22,3 +22,5 @@ #include #include #include +#include +#include diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp index a3fa0938..efe9bca8 100644 --- a/src/CalcViewModel/ApplicationViewModel.cpp +++ b/src/CalcViewModel/ApplicationViewModel.cpp @@ -85,7 +85,7 @@ void ApplicationViewModel::Initialize(ViewMode mode) } catch (const std::exception& e) { - TraceLogger::GetInstance().LogStandardException(mode, __FUNCTIONW__, e); + TraceLogger::GetInstance()->LogStandardException(mode, __FUNCTIONW__, e); if (!TryRecoverFromNavigationModeFailure()) { // Could not navigate to standard mode either. @@ -95,7 +95,7 @@ void ApplicationViewModel::Initialize(ViewMode mode) } catch (Exception ^ e) { - TraceLogger::GetInstance().LogPlatformException(mode, __FUNCTIONW__, e); + TraceLogger::GetInstance()->LogPlatformException(mode, __FUNCTIONW__, e); if (!TryRecoverFromNavigationModeFailure()) { // Could not navigate to standard mode either. @@ -152,7 +152,7 @@ void ApplicationViewModel::OnModeChanged() } auto resProvider = AppResourceProvider::GetInstance(); - CategoryName = resProvider.GetResourceString(NavCategory::GetNameResourceKey(m_mode)); + CategoryName = resProvider->GetResourceString(NavCategory::GetNameResourceKey(m_mode)); // Cast mode to an int in order to save it to app data. // Save the changed mode, so that the new window launches in this mode. @@ -162,11 +162,11 @@ void ApplicationViewModel::OnModeChanged() // Log ModeChange event when not first launch, log WindowCreated on first launch if (NavCategory::IsValidViewMode(m_PreviousMode)) { - TraceLogger::GetInstance().LogModeChange(m_mode); + TraceLogger::GetInstance()->LogModeChange(m_mode); } else { - TraceLogger::GetInstance().LogWindowCreated(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); + TraceLogger::GetInstance()->LogWindowCreated(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); } RaisePropertyChanged(ClearMemoryVisibilityPropertyName); diff --git a/src/CalcViewModel/ApplicationViewModel.h b/src/CalcViewModel/ApplicationViewModel.h index c35595e9..8a293eac 100644 --- a/src/CalcViewModel/ApplicationViewModel.h +++ b/src/CalcViewModel/ApplicationViewModel.h @@ -23,10 +23,11 @@ namespace CalculatorApp OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel ^, DateCalcViewModel); OBSERVABLE_PROPERTY_RW(UnitConverterViewModel ^, ConverterViewModel); OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode); + OBSERVABLE_PROPERTY_R(bool, IsAlwaysOnTop); OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, CategoryName); // Indicates whether calculator is currently in standard mode _and_ supports CompactOverlay _and_ is not in Always-on-Top mode - OBSERVABLE_PROPERTY_RW(bool, DisplayNormalAlwaysOnTopOption); + OBSERVABLE_PROPERTY_R(bool, DisplayNormalAlwaysOnTopOption); COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand); COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand); @@ -91,22 +92,6 @@ namespace CalculatorApp } } - property bool IsAlwaysOnTop - { - bool get() - { - return m_isAlwaysOnTop; - } - void set(bool value) - { - if (m_isAlwaysOnTop != value) - { - m_isAlwaysOnTop = value; - RaisePropertyChanged(L"IsAlwaysOnTop"); - } - } - } - void ToggleAlwaysOnTop(float width, float height); private: @@ -123,8 +108,6 @@ namespace CalculatorApp Windows::Foundation::Collections::IObservableVector ^ m_categories; Concurrency::task HandleToggleAlwaysOnTop(float width, float height); void SetDisplayNormalAlwaysOnTopOption(); - - bool m_isAlwaysOnTop; }; } } diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj index c9fae3ce..49bc036f 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ b/src/CalcViewModel/CalcViewModel.vcxproj @@ -315,13 +315,10 @@ - - - - + @@ -340,6 +337,7 @@ + @@ -357,16 +355,12 @@ - - - - @@ -401,7 +395,6 @@ - @@ -431,12 +424,12 @@ - + - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see https://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + - + \ No newline at end of file diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters index bd0d75f6..ac5d41d3 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters @@ -20,7 +20,6 @@ - Common @@ -69,21 +68,9 @@ Common - - Common\Automation - - - Common\Automation - - - Common\Automation - Common\Automation - - Common\Automation - DataLoaders @@ -93,6 +80,9 @@ DataLoaders + + Common\Automation + @@ -104,7 +94,6 @@ - Common @@ -177,24 +166,9 @@ Common - - Common\Automation - - - Common\Automation - - - Common\Automation - - - Common\Automation - Common\Automation - - Common\Automation - DataLoaders @@ -216,8 +190,14 @@ DataLoaders - - DataLoaders + + Common\Automation + + + Common + + + Common @@ -226,4 +206,7 @@ + + + \ No newline at end of file diff --git a/src/CalcViewModel/Common/AppResourceProvider.cpp b/src/CalcViewModel/Common/AppResourceProvider.cpp index a75a375f..b843d55b 100644 --- a/src/CalcViewModel/Common/AppResourceProvider.cpp +++ b/src/CalcViewModel/Common/AppResourceProvider.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -14,9 +14,9 @@ AppResourceProvider::AppResourceProvider() m_cEngineStringResLoader = ResourceLoader::GetForViewIndependentUse(L"CEngineStrings"); } -AppResourceProvider& AppResourceProvider::GetInstance() +AppResourceProvider ^ AppResourceProvider::GetInstance() { - static AppResourceProvider s_instance; + static AppResourceProvider ^ s_instance = ref new AppResourceProvider(); return s_instance; } diff --git a/src/CalcViewModel/Common/AppResourceProvider.h b/src/CalcViewModel/Common/AppResourceProvider.h index 8876fb91..be429a13 100644 --- a/src/CalcViewModel/Common/AppResourceProvider.h +++ b/src/CalcViewModel/Common/AppResourceProvider.h @@ -1,14 +1,14 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once namespace CalculatorApp { - class AppResourceProvider + public ref class AppResourceProvider sealed { public: - static AppResourceProvider& GetInstance(); + static AppResourceProvider ^ GetInstance(); Platform::String ^ GetResourceString(_In_ Platform::String ^ key); Platform::String ^ GetCEngineString(_In_ Platform::String ^ key); diff --git a/src/CalcViewModel/Common/Automation/INarratorAnnouncementHost.h b/src/CalcViewModel/Common/Automation/INarratorAnnouncementHost.h deleted file mode 100644 index 9f947f41..00000000 --- a/src/CalcViewModel/Common/Automation/INarratorAnnouncementHost.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "NarratorAnnouncement.h" - -// Declaration of the INarratorAnnouncementHost interface. -// This interface exists to hide the concrete announcement host -// being used. Depending on the version of the OS the app is running on, -// the app may need a host that uses LiveRegionChanged or RaiseNotification. - -namespace CalculatorApp::Common::Automation -{ -public - interface class INarratorAnnouncementHost - { - public: - // Is the host available on this OS. - bool IsHostAvailable(); - - // Make a new instance of a concrete host. - INarratorAnnouncementHost ^ MakeHost(); - - // Make an announcement using the concrete host's preferred method. - void Announce(NarratorAnnouncement ^ announcement); - }; -} diff --git a/src/CalcViewModel/Common/Automation/LiveRegionHost.cpp b/src/CalcViewModel/Common/Automation/LiveRegionHost.cpp deleted file mode 100644 index 0df3a96c..00000000 --- a/src/CalcViewModel/Common/Automation/LiveRegionHost.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "LiveRegionHost.h" - -using namespace CalculatorApp::Common::Automation; -using namespace Windows::UI::Xaml::Automation; -using namespace Windows::UI::Xaml::Automation::Peers; -using namespace Windows::UI::Xaml::Controls; - -LiveRegionHost::LiveRegionHost() - : m_host(nullptr) -{ -} - -bool LiveRegionHost::IsHostAvailable() -{ - // LiveRegion is always available. - return true; -} - -INarratorAnnouncementHost ^ LiveRegionHost::MakeHost() -{ - return ref new LiveRegionHost(); -} - -void LiveRegionHost::Announce(NarratorAnnouncement ^ announcement) -{ - if (m_host == nullptr) - { - m_host = ref new TextBlock(); - AutomationProperties::SetLiveSetting(m_host, AutomationLiveSetting::Assertive); - } - - AutomationProperties::SetName(m_host, announcement->Announcement); - AutomationPeer ^ peer = FrameworkElementAutomationPeer::FromElement(m_host); - if (peer != nullptr) - { - peer->RaiseAutomationEvent(AutomationEvents::LiveRegionChanged); - } -} diff --git a/src/CalcViewModel/Common/Automation/LiveRegionHost.h b/src/CalcViewModel/Common/Automation/LiveRegionHost.h deleted file mode 100644 index fef7c714..00000000 --- a/src/CalcViewModel/Common/Automation/LiveRegionHost.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "INarratorAnnouncementHost.h" - -// Declaration of the LiveRegionHost class. -// This class announces NarratorAnnouncements using the LiveRegionChanged event. -// This event is unreliable and should be deprecated in favor of the new -// RaiseNotification API in RS3. - -namespace CalculatorApp::Common::Automation -{ - // This class exists so that the app can run on RS2 and use LiveRegions - // to host notifications on those builds. - // When the app switches to min version RS3, this class can be removed - // and the app will switch to using the Notification API. - // TODO - MSFT 12735088 -public - ref class LiveRegionHost sealed : public INarratorAnnouncementHost - { - public: - LiveRegionHost(); - - virtual bool IsHostAvailable(); - virtual INarratorAnnouncementHost ^ MakeHost(); - - virtual void Announce(NarratorAnnouncement ^ announcement); - - private: - Windows::UI::Xaml::UIElement ^ m_host; - }; -} diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp b/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp index 5b6d99bd..940c88c9 100644 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp +++ b/src/CalcViewModel/Common/Automation/NarratorAnnouncement.cpp @@ -6,6 +6,7 @@ using namespace CalculatorApp::Common::Automation; using namespace Platform; +using namespace Windows::UI::Xaml::Automation::Peers; namespace CalculatorApp::Common::Automation { diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h b/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h index c4c0c526..fef7e260 100644 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h +++ b/src/CalcViewModel/Common/Automation/NarratorAnnouncement.h @@ -5,32 +5,6 @@ namespace CalculatorApp::Common::Automation { - // These enum types are copied from the types available in - // Windows::UI::Xaml::Automation::Peers in the RS3 SDK. - // When this app switches to min version RS3, these custom - // enums should be removed and the Windows types should be used - // instead. - // TODO - MSFT 12735088 -public - enum class AutomationNotificationKind - { - ItemAdded = 0, - ItemRemoved = 1, - ActionCompleted = 2, - ActionAborted = 3, - Other = 4 - }; - -public - enum class AutomationNotificationProcessing - { - ImportantAll = 0, - ImportantMostRecent = 1, - All = 2, - MostRecent = 3, - CurrentThenMostRecent = 4 - }; - public ref class NarratorAnnouncement sealed { @@ -41,14 +15,14 @@ public property Platform::String ^ ActivityId { Platform::String ^ get(); } - property AutomationNotificationKind Kind + property Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind Kind { - AutomationNotificationKind get(); + Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind get(); } - property AutomationNotificationProcessing Processing + property Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing Processing { - AutomationNotificationProcessing get(); + Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing get(); } static bool IsValid(NarratorAnnouncement ^ announcement); @@ -61,13 +35,13 @@ public NarratorAnnouncement( Platform::String ^ announcement, Platform::String ^ activityId, - AutomationNotificationKind kind, - AutomationNotificationProcessing processing); + Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind kind, + Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing processing); Platform::String ^ m_announcement; Platform::String ^ m_activityId; - AutomationNotificationKind m_kind; - AutomationNotificationProcessing m_processing; + Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind m_kind; + Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing m_processing; }; // CalculatorAnnouncement is intended to contain only static methods diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.cpp b/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.cpp deleted file mode 100644 index a103c7e7..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NarratorAnnouncementHostFactory.h" -#include "NotificationHost.h" -#include "LiveRegionHost.h" - -using namespace CalculatorApp::Common::Automation; -using namespace std; - -INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::s_hostProducer; -vector NarratorAnnouncementHostFactory::s_hosts; - -// This static variable is used only to call the initialization function, to initialize the other static variables. -int NarratorAnnouncementHostFactory::s_init = NarratorAnnouncementHostFactory::Initialize(); -int NarratorAnnouncementHostFactory::Initialize() -{ - RegisterHosts(); - NarratorAnnouncementHostFactory::s_hostProducer = GetHostProducer(); - - return 0; -} - -// For now, there are two type of announcement hosts. -// We'd prefer to use Notification if it's available and fall back to LiveRegion -// if not. The availability of the host depends on the version of the OS the app is running on. -// When the app switches to min version RS3, the LiveRegionHost can be removed and we will always -// use NotificationHost. -// TODO - MSFT 12735088 -void NarratorAnnouncementHostFactory::RegisterHosts() -{ - // The host that will be used is the first available host, - // therefore, order of hosts is important here. - NarratorAnnouncementHostFactory::s_hosts = { ref new NotificationHost(), ref new LiveRegionHost() }; -} - -INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::GetHostProducer() -{ - for (INarratorAnnouncementHost ^ host : NarratorAnnouncementHostFactory::s_hosts) - { - if (host->IsHostAvailable()) - { - return host; - } - } - - assert(false && L"No suitable AnnouncementHost was found."); - return nullptr; -} - -INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::MakeHost() -{ - if (NarratorAnnouncementHostFactory::s_hostProducer == nullptr) - { - assert(false && L"No host producer has been assigned."); - return nullptr; - } - - return NarratorAnnouncementHostFactory::s_hostProducer->MakeHost(); -} diff --git a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.h b/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.h deleted file mode 100644 index 4b739a79..00000000 --- a/src/CalcViewModel/Common/Automation/NarratorAnnouncementHostFactory.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "INarratorAnnouncementHost.h" - -// Declaration of the NarratorAnnouncementHostFactory class. -// This class exists to hide the construction of a concrete INarratorAnnouncementHost. -// Depending on the version of the OS the app is running on, the factory will return -// an announcement host appropriate for that version. - -namespace CalculatorApp::Common::Automation -{ - class NarratorAnnouncementHostFactory - { - public: - static INarratorAnnouncementHost ^ MakeHost(); - - private: - NarratorAnnouncementHostFactory() - { - } - - static int Initialize(); - static void RegisterHosts(); - static INarratorAnnouncementHost ^ GetHostProducer(); - - private: - static int s_init; - static INarratorAnnouncementHost ^ s_hostProducer; - static std::vector s_hosts; - }; -} diff --git a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp index bc146e68..89fa0c0b 100644 --- a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp +++ b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp @@ -5,7 +5,6 @@ #include "pch.h" #include "NarratorNotifier.h" -#include "NarratorAnnouncementHostFactory.h" using namespace CalculatorApp::Common::Automation; using namespace Platform; @@ -17,14 +16,22 @@ DependencyProperty ^ NarratorNotifier::s_announcementProperty; NarratorNotifier::NarratorNotifier() { - m_announcementHost = NarratorAnnouncementHostFactory::MakeHost(); } void NarratorNotifier::Announce(NarratorAnnouncement ^ announcement) { - if (NarratorAnnouncement::IsValid(announcement) && m_announcementHost != nullptr) + if (NarratorAnnouncement::IsValid(announcement)) { - m_announcementHost->Announce(announcement); + if (m_announcementElement == nullptr) + { + m_announcementElement = ref new Windows::UI::Xaml::Controls::TextBlock(); + } + + auto peer = FrameworkElementAutomationPeer::FromElement(m_announcementElement); + if (peer != nullptr) + { + peer->RaiseNotificationEvent(announcement->Kind, announcement->Processing, announcement->Announcement, announcement->ActivityId); + } } } diff --git a/src/CalcViewModel/Common/Automation/NarratorNotifier.h b/src/CalcViewModel/Common/Automation/NarratorNotifier.h index 55bed4e7..359bb09e 100644 --- a/src/CalcViewModel/Common/Automation/NarratorNotifier.h +++ b/src/CalcViewModel/Common/Automation/NarratorNotifier.h @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Declaration of the NarratorNotifier class. #pragma once -#include "INarratorAnnouncementHost.h" +#include "NarratorAnnouncement.h" namespace CalculatorApp::Common::Automation { @@ -47,6 +47,6 @@ public static Windows::UI::Xaml::DependencyProperty ^ s_announcementProperty; private: - INarratorAnnouncementHost ^ m_announcementHost; + Windows::UI::Xaml::UIElement ^ m_announcementElement; }; } diff --git a/src/CalcViewModel/Common/Automation/NotificationHost.cpp b/src/CalcViewModel/Common/Automation/NotificationHost.cpp deleted file mode 100644 index 92bf846e..00000000 --- a/src/CalcViewModel/Common/Automation/NotificationHost.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "NotificationHost.h" - -using namespace CalculatorApp::Common::Automation; -using namespace Windows::Foundation::Metadata; -using namespace Windows::UI::Xaml::Automation; -using namespace Windows::UI::Xaml::Automation::Peers; -using namespace Windows::UI::Xaml::Controls; - -NotificationHost::NotificationHost() - : m_host(nullptr) -{ -} - -bool NotificationHost::IsHostAvailable() -{ - return ApiInformation::IsMethodPresent(L"Windows.UI.Xaml.Automation.Peers.AutomationPeer", L"RaiseNotificationEvent"); -} - -INarratorAnnouncementHost ^ NotificationHost::MakeHost() -{ - return ref new NotificationHost(); -} - -void NotificationHost::Announce(NarratorAnnouncement ^ announcement) -{ - if (m_host == nullptr) - { - m_host = ref new TextBlock(); - } - - auto peer = FrameworkElementAutomationPeer::FromElement(m_host); - if (peer != nullptr) - { - peer->RaiseNotificationEvent( - GetWindowsNotificationKind(announcement->Kind), - GetWindowsNotificationProcessing(announcement->Processing), - announcement->Announcement, - announcement->ActivityId); - } -} - -StandardPeers::AutomationNotificationKind NotificationHost::GetWindowsNotificationKind(CustomPeers::AutomationNotificationKind customKindType) -{ - switch (customKindType) - { - case CustomPeers::AutomationNotificationKind::ItemAdded: - return StandardPeers::AutomationNotificationKind::ItemAdded; - - case CustomPeers::AutomationNotificationKind::ItemRemoved: - return StandardPeers::AutomationNotificationKind::ItemRemoved; - - case CustomPeers::AutomationNotificationKind::ActionCompleted: - return StandardPeers::AutomationNotificationKind::ActionCompleted; - - case CustomPeers::AutomationNotificationKind::ActionAborted: - return StandardPeers::AutomationNotificationKind::ActionAborted; - - case CustomPeers::AutomationNotificationKind::Other: - return StandardPeers::AutomationNotificationKind::Other; - - default: - assert(false && L"Unexpected AutomationNotificationKind"); - } - - return StandardPeers::AutomationNotificationKind::Other; -} - -StandardPeers::AutomationNotificationProcessing -NotificationHost::GetWindowsNotificationProcessing(CustomPeers::AutomationNotificationProcessing customProcessingType) -{ - switch (customProcessingType) - { - case CustomPeers::AutomationNotificationProcessing::ImportantAll: - return StandardPeers::AutomationNotificationProcessing::ImportantAll; - - case CustomPeers::AutomationNotificationProcessing::ImportantMostRecent: - return StandardPeers::AutomationNotificationProcessing::ImportantMostRecent; - - case CustomPeers::AutomationNotificationProcessing::All: - return StandardPeers::AutomationNotificationProcessing::All; - - case CustomPeers::AutomationNotificationProcessing::MostRecent: - return StandardPeers::AutomationNotificationProcessing::MostRecent; - - case CustomPeers::AutomationNotificationProcessing::CurrentThenMostRecent: - return StandardPeers::AutomationNotificationProcessing::CurrentThenMostRecent; - - default: - assert(false && L"Unexpected AutomationNotificationProcessing"); - } - - return StandardPeers::AutomationNotificationProcessing::ImportantMostRecent; -} diff --git a/src/CalcViewModel/Common/Automation/NotificationHost.h b/src/CalcViewModel/Common/Automation/NotificationHost.h deleted file mode 100644 index d0a929c6..00000000 --- a/src/CalcViewModel/Common/Automation/NotificationHost.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include "INarratorAnnouncementHost.h" - -// Declaration of the NotificationHost class. -// This class announces NarratorAnnouncements using the RaiseNotification API -// available in RS3. - -namespace CalculatorApp::Common::Automation -{ -public - ref class NotificationHost sealed : public INarratorAnnouncementHost - { - public: - NotificationHost(); - - virtual bool IsHostAvailable(); - virtual INarratorAnnouncementHost ^ MakeHost(); - - virtual void Announce(NarratorAnnouncement ^ announcement); - - private: - static Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind - GetWindowsNotificationKind(CalculatorApp::Common::Automation::AutomationNotificationKind customKindType); - - static Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing - GetWindowsNotificationProcessing(CalculatorApp::Common::Automation::AutomationNotificationProcessing customProcessingType); - - private: - Windows::UI::Xaml::UIElement ^ m_host; - }; -} diff --git a/src/CalcViewModel/Common/BitLength.h b/src/CalcViewModel/Common/BitLength.h new file mode 100644 index 00000000..8c38e7e4 --- /dev/null +++ b/src/CalcViewModel/Common/BitLength.h @@ -0,0 +1,17 @@ +#pragma once + +namespace CalculatorApp +{ + namespace Common + { + public + enum class BitLength : int + { + BitLengthUnknown = -1, + BitLengthByte = 8, + BitLengthWord = 16, + BitLengthDWord = 32, + BitLengthQWord = 64, + }; + } +} diff --git a/src/CalcViewModel/Common/CalculatorButtonUser.h b/src/CalcViewModel/Common/CalculatorButtonUser.h index b9ce3329..113d34dc 100644 --- a/src/CalcViewModel/Common/CalculatorButtonUser.h +++ b/src/CalcViewModel/Common/CalculatorButtonUser.h @@ -94,6 +94,32 @@ public Byte = (int)CM::Command::CommandByte, Cube = (int)CM::Command::CommandCUB, DMS = (int)CM::Command::CommandDMS, + Hyp = (int) CM::Command::CommandHYP, + Sec = (int) CM::Command::CommandSEC, + Csc = (int) CM::Command::CommandCSC, + Cot = (int) CM::Command::CommandCOT, + InvSec = (int) CM::Command::CommandASEC, + InvCsc = (int) CM::Command::CommandACSC, + InvCot = (int) CM::Command::CommandACOT, + Sech = (int) CM::Command::CommandSECH, + Csch = (int) CM::Command::CommandCSCH, + Coth = (int) CM::Command::CommandCOTH, + InvSech = (int) CM::Command::CommandASECH, + InvCsch = (int) CM::Command::CommandACSCH, + InvCoth = (int) CM::Command::CommandACOTH, + CubeRoot = (int) CM::Command::CommandCUBEROOT, + TwoPowerX = (int) CM::Command::CommandPOW2, + LogBaseX = (int) CM::Command::CommandLogBaseX, + Nand = (int) CM::Command::CommandNand, + Nor = (int) CM::Command::CommandNor, + Abs = (int) CM::Command::CommandAbs, + Floor = (int) CM::Command::CommandFloor, + Ceil = (int) CM::Command::CommandCeil, + Rand = (int) CM::Command::CommandRand, + Euler = (int) CM::Command::CommandEuler, + RshL = (int)CM::Command::CommandRSHFL, + RolC = (int)CM::Command::CommandROLC, + RorC = (int)CM::Command::CommandRORC, BINSTART = (int)CM::Command::CommandBINEDITSTART, BINPOS0 = (int)CM::Command::CommandBINPOS0, @@ -161,7 +187,6 @@ public BINPOS62 = (int)CM::Command::CommandBINPOS62, BINPOS63 = (int)CM::Command::CommandBINPOS63, BINEND = (int)CM::Command::CommandBINEDITEND, - Hyp = (int)CM::Command::CommandHYP, // Enum values below are used for Tracelogging and do not map to the Calculator engine MemoryAdd = (int)CM::Command::CommandMPLUS, diff --git a/src/CalcViewModel/Common/CalculatorDisplay.cpp b/src/CalcViewModel/Common/CalculatorDisplay.cpp index 91892dda..5cf8afbc 100644 --- a/src/CalcViewModel/Common/CalculatorDisplay.cpp +++ b/src/CalcViewModel/Common/CalculatorDisplay.cpp @@ -9,6 +9,7 @@ using namespace CalculatorApp; using namespace CalculationManager; +using namespace Platform; using namespace std; CalculatorDisplay::CalculatorDisplay() @@ -31,7 +32,7 @@ void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue { if (auto calcVM = m_callbackReference.Resolve()) { - calcVM->SetPrimaryDisplay(displayStringValue, isError); + calcVM->SetPrimaryDisplay(StringReference(displayStringValue.c_str()), isError); } } } @@ -70,8 +71,8 @@ void CalculatorDisplay::SetIsInError(bool isError) } void CalculatorDisplay::SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands) + _Inout_ std::shared_ptr>> const& tokens, + _Inout_ std::shared_ptr>> const& commands) { if (m_callbackReference != nullptr) { @@ -136,3 +137,14 @@ void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory) } } } + +void CalculatorDisplay::InputChanged() +{ + if (m_callbackReference != nullptr) + { + if (auto calcVM = m_callbackReference.Resolve()) + { + calcVM->OnInputChanged(); + } + } +} diff --git a/src/CalcViewModel/Common/CalculatorDisplay.h b/src/CalcViewModel/Common/CalculatorDisplay.h index 93865c96..921260da 100644 --- a/src/CalcViewModel/Common/CalculatorDisplay.h +++ b/src/CalcViewModel/Common/CalculatorDisplay.h @@ -19,8 +19,8 @@ namespace CalculatorApp void SetPrimaryDisplay(_In_ const std::wstring& displayString, _In_ bool isError) override; void SetIsInError(bool isError) override; void SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands) override; + _Inout_ std::shared_ptr>> const& tokens, + _Inout_ std::shared_ptr>> const& commands) override; void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override; void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override; @@ -28,6 +28,7 @@ namespace CalculatorApp void MaxDigitsReached() override; void BinaryOperatorReceived() override; void MemoryItemChanged(unsigned int indexOfMemory) override; + void InputChanged() override; private: Platform::WeakReference m_callbackReference; diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp index 8c00d417..ade3a3fb 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.cpp +++ b/src/CalcViewModel/Common/CopyPasteManager.cpp @@ -11,13 +11,18 @@ using namespace concurrency; using namespace CalculatorApp; using namespace CalculatorApp::Common; using namespace Platform; +using namespace Platform::Collections; using namespace Windows::Foundation; using namespace Windows::System; using namespace Windows::ApplicationModel::DataTransfer; +using namespace Windows::Foundation::Collections; -String ^ CopyPasteManager::supportedFormats[] = { StandardDataFormats::Text }; +StringReference PasteErrorString(L"NoOp"); -static constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" }; +static const wstring c_validBasicCharacterSet = L"0123456789+-.e"; +static const wstring c_validStandardCharacterSet = c_validBasicCharacterSet + L"*/"; +static const wstring c_validScientificCharacterSet = c_validStandardCharacterSet + L"()^%"; +static const wstring c_validProgrammerCharacterSet = c_validStandardCharacterSet + L"()%abcdfABCDEF"; // The below values can not be "constexpr"-ed, // as both wstring_view and wchar[] can not be concatenated @@ -26,7 +31,8 @@ static const wstring c_wspc = L"[\\s\\x85]*"; static const wstring c_wspcLParens = c_wspc + L"[(]*" + c_wspc; static const wstring c_wspcLParenSigned = c_wspc + L"([-+]?[(])*" + c_wspc; static const wstring c_wspcRParens = c_wspc + L"[)]*" + c_wspc; -static const wstring c_signedDecFloat = L"[-+]?\\d*(\\d|[.])\\d*"; +static const wstring c_signedDecFloat = L"(?:[-+]?(?:\\d+(\\.\\d*)?|\\.\\d+))"; +static const wstring c_optionalENotation = L"(?:e[+-]?\\d+)?"; // Programmer Mode Integer patterns // Support digit separators ` (WinDbg/MASM), ' (C++), and _ (C# and other languages) @@ -37,11 +43,9 @@ static const wstring c_binProgrammerChars = L"[0-1]+((_|'|`)[0-1]+)*"; static const wstring c_uIntSuffixes = L"[uU]?[lL]{0,2}"; // RegEx Patterns used by various modes -static const array standardModePatterns = { wregex(c_wspc + c_signedDecFloat + c_wspc) }; -static const array scientificModePatterns = { - wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_wspcRParens), - wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + L"e[+-]?\\d+" + c_wspcRParens) -}; +static const array standardModePatterns = { wregex(c_wspc + c_signedDecFloat + c_optionalENotation + c_wspc) }; +static const array scientificModePatterns = { wregex( + L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_optionalENotation + c_wspcRParens) }; static const array, 4> programmerModePatterns = { { // Hex numbers like 5F, 4A0C, 0xa9, 0xFFull, 47CDh { wregex(c_wspcLParens + L"(0[xX])?" + c_hexProgrammerChars + c_uIntSuffixes + c_wspcRParens), @@ -55,7 +59,7 @@ static const array, 4> programmerModePatterns = { { wregex(c_wspcLParens + L"(0[byBY])?" + c_binProgrammerChars + c_uIntSuffixes + c_wspcRParens), wregex(c_wspcLParens + c_binProgrammerChars + L"[bB]?" + c_wspcRParens) } } }; -static const array unitConverterPatterns = { wregex(c_wspc + L"[-+]?\\d*[.]?\\d*" + c_wspc) }; +static const array unitConverterPatterns = { wregex(c_wspc + c_signedDecFloat + c_wspc) }; void CopyPasteManager::CopyToClipboard(String ^ stringToCopy) { @@ -65,7 +69,7 @@ void CopyPasteManager::CopyToClipboard(String ^ stringToCopy) Clipboard::SetContent(dataPackage); } -task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) +IAsyncOperation ^ CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupType modeType, NumberBase programmerNumberBase, BitLength bitLengthType) { // Retrieve the text in the clipboard auto dataPackageView = Clipboard::GetContent(); @@ -75,51 +79,47 @@ task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupTy //-- add support to allow pasting for expressions like .2 , -.2 //-- add support to allow pasting for expressions like 1.3e12(as of now we allow 1.3e+12) - return create_task((dataPackageView->GetTextAsync(::StandardDataFormats::Text))) - .then( - [mode, modeType, programmerNumberBase, bitLengthType](String ^ pastedText) { - return ValidatePasteExpression(pastedText, mode, modeType, programmerNumberBase, bitLengthType); - }, - task_continuation_context::use_arbitrary()); + return create_async([dataPackageView, mode, modeType, programmerNumberBase, bitLengthType] { + return create_task(dataPackageView->GetTextAsync(::StandardDataFormats::Text)) + .then( + [mode, modeType, programmerNumberBase, bitLengthType](String ^ pastedText) { + return ValidatePasteExpression(pastedText, mode, modeType, programmerNumberBase, bitLengthType); + }, + task_continuation_context::use_arbitrary()); + }); } -int CopyPasteManager::ClipboardTextFormat() +bool CopyPasteManager::HasStringToPaste() { - const auto dataPackageView = Clipboard::GetContent(); - - for (int i = 0; i < RTL_NUMBER_OF(supportedFormats); i++) - { - if (dataPackageView->Contains(supportedFormats[i])) - { - return i; - } - } - return -1; + return Clipboard::GetContent()->Contains(StandardDataFormats::Text); } -String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, int programmerNumberBase, int bitLengthType) +String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, NumberBase programmerNumberBase, BitLength bitLengthType) { - return CopyPasteManager::ValidatePasteExpression(pastedText, mode, NavCategory::GetGroupType(mode), programmerNumberBase, bitLengthType); + return ValidatePasteExpression(pastedText, mode, NavCategory::GetGroupType(mode), programmerNumberBase, bitLengthType); } // return "NoOp" if pastedText is invalid else return pastedText - -String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) +String + ^ CopyPasteManager::ValidatePasteExpression( + String ^ pastedText, + ViewMode mode, + CategoryGroupType modeType, + NumberBase programmerNumberBase, + BitLength bitLengthType) { if (pastedText->Length() > MaxPasteableLength) { // return NoOp to indicate don't paste anything. - TraceLogger::GetInstance().LogError(mode, L"CopyPasteManager::ValidatePasteExpression", L"PastedExpressionSizeGreaterThanMaxAllowed"); - return StringReference(PasteErrorString); + TraceLogger::GetInstance()->LogError(mode, L"CopyPasteManager::ValidatePasteExpression", L"PastedExpressionSizeGreaterThanMaxAllowed"); + return PasteErrorString; } - wstring pasteExpression = pastedText->Data(); - // Get english translated expression - String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pasteExpression); + String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pastedText); // Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333 - pasteExpression = RemoveUnwantedCharsFromWstring(englishString->Data()); + auto pasteExpression = wstring(RemoveUnwantedCharsFromString(englishString)->Data()); // If the last character is an = sign, remove it from the pasteExpression to allow evaluating the result on paste. if (!pasteExpression.empty() && pasteExpression.back() == L'=') @@ -129,31 +129,32 @@ String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode // Extract operands from the expression to make regex comparison easy and quick. For whole expression it was taking too much of time. // Operands vector will have the list of operands in the pasteExpression - vector operands = ExtractOperands(pasteExpression, mode); - if (operands.empty()) + auto operands = ExtractOperands(StringReference(pasteExpression.c_str()), mode); + if (operands->Size == 0) { // return NoOp to indicate don't paste anything. - return StringReference(PasteErrorString); + return PasteErrorString; } if (modeType == CategoryGroupType::Converter) { - operands = { pasteExpression }; + operands->Clear(); + operands->Append(ref new String(pasteExpression.c_str())); } // validate each operand with patterns for different modes if (!ExpressionRegExMatch(operands, mode, modeType, programmerNumberBase, bitLengthType)) { - TraceLogger::GetInstance().LogError(mode, L"CopyPasteManager::ValidatePasteExpression", L"InvalidExpressionForPresentMode"); - return StringReference(PasteErrorString); + TraceLogger::GetInstance()->LogError(mode, L"CopyPasteManager::ValidatePasteExpression", L"InvalidExpressionForPresentMode"); + return PasteErrorString; } - return ref new String(pastedText->Data()); + return pastedText; } -vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression, ViewMode mode) +IVector ^ CopyPasteManager::ExtractOperands(Platform::String ^ pasteExpression, ViewMode mode) { - vector operands{}; + auto operands = ref new Vector(); size_t lastIndex = 0; bool haveOperator = false; bool startExpCounting = false; @@ -161,51 +162,72 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression bool isPreviousOpenParen = false; bool isPreviousOperator = false; + wstring validCharacterSet; + switch (mode) + { + case ViewMode::Standard: + validCharacterSet = c_validStandardCharacterSet; + break; + case ViewMode::Scientific: + validCharacterSet = c_validScientificCharacterSet; + break; + case ViewMode::Programmer: + validCharacterSet = c_validProgrammerCharacterSet; + break; + default: + validCharacterSet = c_validBasicCharacterSet; + } + // This will have the exponent length size_t expLength = 0; - for (size_t i = 0; i < pasteExpression.length(); i++) + int i = -1; + for (auto currentChar : pasteExpression) { + ++i; // if the current character is not a valid one don't process it - if (c_validCharacterSet.find(pasteExpression.at(i)) == wstring_view::npos) + if (validCharacterSet.find(currentChar) == wstring_view::npos) { continue; } - if (operands.size() >= MaxOperandCount) + if (operands->Size >= MaxOperandCount) { - TraceLogger::GetInstance().LogError(mode, L"CopyPasteManager::ExtractOperands", L"OperandCountGreaterThanMaxCount"); - operands.clear(); + TraceLogger::GetInstance()->LogError(mode, L"CopyPasteManager::ExtractOperands", L"OperandCountGreaterThanMaxCount"); + operands->Clear(); return operands; } - if (startExpCounting) + if (currentChar >= L'0' && currentChar <= L'9') { - if ((pasteExpression.at(i) >= L'0') && (pasteExpression.at(i) <= L'9')) + if (startExpCounting) { expLength++; // to disallow pasting of 1e+12345 as 1e+1234, max exponent that can be pasted is 9999. if (expLength > MaxExponentLength) { - TraceLogger::GetInstance().LogError(mode, L"CopyPasteManager::ExtractOperands", L"ExponentLengthGreaterThanMaxLength"); - operands.clear(); + TraceLogger::GetInstance()->LogError(mode, L"CopyPasteManager::ExtractOperands", L"ExponentLengthGreaterThanMaxLength"); + operands->Clear(); return operands; } } + isPreviousOperator = false; } - - if ((mode != ViewMode::Programmer) && (pasteExpression.at(i) == L'e')) + else if (currentChar == L'e') { - startExpCounting = true; + if (mode != ViewMode::Programmer) + { + startExpCounting = true; + } + isPreviousOperator = false; } - - if (((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-') || (pasteExpression.at(i) == L'*') || (pasteExpression.at(i) == L'/'))) + else if (currentChar == L'+' || currentChar == L'-' || currentChar == L'*' || currentChar == L'/' || currentChar == L'^' || currentChar == L'%') { - if ((pasteExpression.at(i) == L'+') || (pasteExpression.at(i) == L'-')) + if (currentChar == L'+' || currentChar == L'-') { // don't break the expression into operands if the encountered character corresponds to sign command(+-) if (isPreviousOpenParen || startOfExpression || isPreviousOperator - || ((mode != ViewMode::Programmer) && !((i != 0) && (pasteExpression.at(i - 1) != L'e')))) + || ((mode != ViewMode::Programmer) && !((i != 0) && pasteExpression->Data()[i - 1] != L'e'))) { isPreviousOperator = false; continue; @@ -216,7 +238,7 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression expLength = 0; haveOperator = true; isPreviousOperator = true; - operands.push_back(pasteExpression.substr(lastIndex, i - lastIndex)); + operands->Append(ref new String(wstring(pasteExpression->Data()).substr(lastIndex, i - lastIndex).c_str())); lastIndex = i + 1; } else @@ -224,26 +246,31 @@ vector CopyPasteManager::ExtractOperands(const wstring& pasteExpression isPreviousOperator = false; } - isPreviousOpenParen = (pasteExpression.at(i) == L'('); + isPreviousOpenParen = (currentChar == L'('); startOfExpression = false; } if (!haveOperator) { - operands.clear(); - operands.push_back(pasteExpression); + operands->Clear(); + operands->Append(pasteExpression); } else { - operands.push_back(pasteExpression.substr(lastIndex, pasteExpression.length() - 1)); + operands->Append(ref new String(wstring(pasteExpression->Data()).substr(lastIndex, pasteExpression->Length() - 1).c_str())); } return operands; } -bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) +bool CopyPasteManager::ExpressionRegExMatch( + IVector ^ operands, + ViewMode mode, + CategoryGroupType modeType, + NumberBase programmerNumberBase, + BitLength bitLengthType) { - if (operands.empty()) + if (operands->Size == 0) { return false; } @@ -260,14 +287,16 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m } else if (mode == ViewMode::Programmer) { - patterns.assign(programmerModePatterns[programmerNumberBase - HexBase].begin(), programmerModePatterns[programmerNumberBase - HexBase].end()); + patterns.assign( + programmerModePatterns[(int)programmerNumberBase - (int)NumberBase::HexBase].begin(), + programmerModePatterns[(int)programmerNumberBase - (int)NumberBase::HexBase].end()); } else if (modeType == CategoryGroupType::Converter) { patterns.assign(unitConverterPatterns.begin(), unitConverterPatterns.end()); } - const auto [maxOperandLength, maxOperandValue] = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType); + auto maxOperandLengthAndValue = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType); bool expMatched = true; for (const auto& operand : operands) @@ -276,34 +305,34 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m bool operandMatched = false; for (const auto& pattern : patterns) { - operandMatched = operandMatched || regex_match(operand, pattern); + operandMatched = operandMatched || regex_match(operand->Data(), pattern); } if (operandMatched) { // Remove characters that are valid in the expression but we do not want to include in length calculations // or which will break conversion from string-to-ULL. - const wstring operandValue = SanitizeOperand(operand); + auto operandValue = SanitizeOperand(operand); // If an operand exceeds the maximum length allowed, break and return. - if (OperandLength(operandValue, mode, modeType, programmerNumberBase) > maxOperandLength) + if (OperandLength(operandValue, mode, modeType, programmerNumberBase) > maxOperandLengthAndValue.maxLength) { expMatched = false; break; } // If maxOperandValue is set and the operandValue exceeds it, break and return. - if (maxOperandValue != 0) + if (maxOperandLengthAndValue.maxValue != 0) { - unsigned long long int operandAsULL = 0; - if (!TryOperandToULL(operandValue, programmerNumberBase, operandAsULL)) + auto operandAsULL = TryOperandToULL(operandValue, programmerNumberBase); + if (operandAsULL == nullptr) { // Operand was empty, received invalid_argument, or received out_of_range. Input is invalid. expMatched = false; break; } - if (operandAsULL > maxOperandValue) + if (operandAsULL->Value > maxOperandLengthAndValue.maxValue) { expMatched = false; break; @@ -317,34 +346,39 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m return expMatched; } -pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) +CopyPasteMaxOperandLengthAndValue +CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mode, CategoryGroupType modeType, NumberBase programmerNumberBase, BitLength bitLengthType) { constexpr size_t defaultMaxOperandLength = 0; constexpr uint64_t defaultMaxValue = 0; - + CopyPasteMaxOperandLengthAndValue res; if (mode == ViewMode::Standard) { - return make_pair(MaxStandardOperandLength, defaultMaxValue); + res.maxLength = MaxStandardOperandLength; + res.maxValue = defaultMaxValue; + return res; } else if (mode == ViewMode::Scientific) { - return make_pair(MaxScientificOperandLength, defaultMaxValue); + res.maxLength = MaxScientificOperandLength; + res.maxValue = defaultMaxValue; + return res; } else if (mode == ViewMode::Programmer) { unsigned int bitLength = 0; switch (bitLengthType) { - case QwordType: + case BitLength::BitLengthQWord: bitLength = 64; break; - case DwordType: + case BitLength::BitLengthDWord: bitLength = 32; break; - case WordType: + case BitLength::BitLengthWord: bitLength = 16; break; - case ByteType: + case BitLength::BitLengthByte: bitLength = 8; break; } @@ -352,65 +386,69 @@ pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mo double bitsPerDigit = 0; switch (programmerNumberBase) { - case BinBase: + case NumberBase::BinBase: bitsPerDigit = log2(2); break; - case OctBase: + case NumberBase::OctBase: bitsPerDigit = log2(8); break; - case DecBase: + case NumberBase::DecBase: bitsPerDigit = log2(10); break; - case HexBase: + case NumberBase::HexBase: bitsPerDigit = log2(16); break; } - unsigned int signBit = (programmerNumberBase == DecBase) ? 1 : 0; + unsigned int signBit = (programmerNumberBase == NumberBase::DecBase) ? 1 : 0; - const auto maxLength = static_cast(ceil((bitLength - signBit) / bitsPerDigit)); + const auto maxLength = static_cast(ceil((bitLength - signBit) / bitsPerDigit)); const uint64_t maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit)); - return make_pair(maxLength, maxValue); + res.maxLength = maxLength; + res.maxValue = maxValue; + return res; } else if (modeType == CategoryGroupType::Converter) { - return make_pair(MaxConverterInputLength, defaultMaxValue); + res.maxLength = MaxConverterInputLength; + res.maxValue = defaultMaxValue; + return res; } - return make_pair(defaultMaxOperandLength, defaultMaxValue); + res.maxLength = defaultMaxOperandLength; + res.maxValue = defaultMaxValue; + return res; } -wstring CopyPasteManager::SanitizeOperand(const wstring& operand) +Platform::String ^ CopyPasteManager::SanitizeOperand(Platform::String ^ operand) { - wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-', L'+' }; + constexpr wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-', L'+' }; - return Utils::RemoveUnwantedCharsFromWstring(operand, unWantedChars, static_cast(size(unWantedChars))); + return ref new String(Utils::RemoveUnwantedCharsFromString(operand->Data(), unWantedChars).c_str()); } -bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, unsigned long long int& result) +IBox ^ CopyPasteManager::TryOperandToULL(String ^ operand, NumberBase numberBase) { - result = 0; - - if (operand.length() == 0 || operand.front() == L'-') + if (operand->Length() == 0 || operand->Data()[0] == L'-') { - return false; + return nullptr; } int intBase; switch (numberBase) { - case HexBase: + case NumberBase::HexBase: intBase = 16; break; - case OctBase: + case NumberBase::OctBase: intBase = 8; break; - case BinBase: + case NumberBase::BinBase: intBase = 2; break; default: - case DecBase: + case NumberBase::DecBase: intBase = 10; break; } @@ -418,8 +456,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u wstring::size_type size = 0; try { - result = stoull(operand, &size, intBase); - return true; + return stoull(operand->Data(), &size, intBase); } catch (const invalid_argument&) { @@ -430,14 +467,14 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u // Do nothing } - return false; + return nullptr; } -size_t CopyPasteManager::OperandLength(const wstring& operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase) +ULONG32 CopyPasteManager::OperandLength(Platform::String ^ operand, ViewMode mode, CategoryGroupType modeType, NumberBase programmerNumberBase) { if (modeType == CategoryGroupType::Converter) { - return operand.length(); + return operand->Length(); } switch (mode) @@ -454,45 +491,46 @@ size_t CopyPasteManager::OperandLength(const wstring& operand, ViewMode mode, Ca } } -size_t CopyPasteManager::StandardScientificOperandLength(const wstring& operand) +ULONG32 CopyPasteManager::StandardScientificOperandLength(Platform::String ^ operand) { - const bool hasDecimal = operand.find('.') != wstring::npos; + auto operandWstring = wstring(operand->Data()); + const bool hasDecimal = operandWstring.find('.') != wstring::npos; if (hasDecimal) { - if (operand.length() >= 2) + if (operandWstring.length() >= 2) { - if ((operand[0] == L'0') && (operand[1] == L'.')) + if ((operandWstring[0] == L'0') && (operandWstring[1] == L'.')) { - return operand.length() - 2; + return static_cast(operandWstring.length() - 2); } else { - return operand.length() - 1; + return static_cast(operandWstring.length() - 1); } } } - return operand.length(); + return static_cast(operandWstring.length()); } -size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int numberBase) +ULONG32 CopyPasteManager::ProgrammerOperandLength(Platform::String ^ operand, NumberBase numberBase) { vector prefixes{}; vector suffixes{}; switch (numberBase) { - case BinBase: + case NumberBase::BinBase: prefixes = { L"0B", L"0Y" }; suffixes = { L"B" }; break; - case DecBase: + case NumberBase::DecBase: prefixes = { L"-", L"0N" }; break; - case OctBase: + case NumberBase::OctBase: prefixes = { L"0T", L"0O" }; break; - case HexBase: + case NumberBase::HexBase: prefixes = { L"0X" }; suffixes = { L"H" }; break; @@ -505,10 +543,10 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num const array uintSuffixes = { L"ULL", L"UL", L"LL", L"U", L"L" }; suffixes.insert(suffixes.end(), uintSuffixes.begin(), uintSuffixes.end()); - wstring operandUpper = operand; + wstring operandUpper = wstring(operand->Data()); transform(operandUpper.begin(), operandUpper.end(), operandUpper.begin(), towupper); - size_t len = operand.length(); + size_t len = operand->Length(); // Detect if there is a suffix and subtract its length // Check suffixes first to allow e.g. "0b" to result in length 1 (value 0), rather than length 0 (no value). @@ -541,7 +579,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num } } - return len; + return static_cast(len); } // return wstring after removing characters like space, comma, double quotes, and monetary prefix currency symbols supported by the Windows keyboard: @@ -556,8 +594,13 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num // Indian rupee(₹) - 8377 // pound(£) - 163 // euro(€) - 8364 -wstring CopyPasteManager::RemoveUnwantedCharsFromWstring(const wstring& input) +Platform::String ^ CopyPasteManager::RemoveUnwantedCharsFromString(Platform::String ^ 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); + constexpr wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237 }; + return ref new String(Utils::RemoveUnwantedCharsFromString(input->Data(), unWantedChars).c_str()); +} + +bool CopyPasteManager::IsErrorMessage(Platform::String ^ message) +{ + return message == PasteErrorString; } diff --git a/src/CalcViewModel/Common/CopyPasteManager.h b/src/CalcViewModel/Common/CopyPasteManager.h index 0359e180..b8850d4c 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.h +++ b/src/CalcViewModel/Common/CopyPasteManager.h @@ -5,6 +5,8 @@ #include "AppResourceProvider.h" #include "NavCategory.h" +#include "BitLength.h" +#include "NumberBase.h" namespace CalculatorUnitTests { @@ -13,78 +15,119 @@ namespace CalculatorUnitTests namespace CalculatorApp { - inline constexpr auto QwordType = 1; - inline constexpr auto DwordType = 2; - inline constexpr auto WordType = 3; - inline constexpr auto ByteType = 4; - inline constexpr auto HexBase = 5; - inline constexpr auto DecBase = 6; - inline constexpr auto OctBase = 7; - inline constexpr auto BinBase = 8; +public + value struct CopyPasteMaxOperandLengthAndValue + { + unsigned int maxLength; + unsigned long long maxValue; + }; - class CopyPasteManager + public ref class CopyPasteManager sealed { public: static void CopyToClipboard(Platform::String ^ stringToCopy); - static concurrency::task GetStringToPaste( - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1, - int bitLengthType = -1); - static bool HasStringToPaste() + static Windows::Foundation::IAsyncOperation< + Platform::String + ^> ^ GetStringToPaste(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, CalculatorApp::Common::NumberBase programmerNumberBase, CalculatorApp::Common::BitLength bitLengthType); + static bool HasStringToPaste(); + static bool IsErrorMessage(Platform::String ^ message); + static property unsigned int MaxPasteableLength { - return ClipboardTextFormat() >= 0; + unsigned int get() + { + return MaxPasteableLengthValue; + } + } + static property unsigned int MaxOperandCount + { + unsigned int get() + { + return MaxOperandCountValue; + } + } + static property unsigned int MaxStandardOperandLength + { + unsigned int get() + { + return MaxStandardOperandLengthValue; + } + } + static property unsigned int MaxScientificOperandLength + { + unsigned int get() + { + return MaxScientificOperandLengthValue; + } } - static constexpr auto PasteErrorString = L"NoOp"; + static property unsigned int MaxConverterInputLength + { + unsigned int get() + { + return MaxConverterInputLengthValue; + } + } + + static property unsigned int MaxExponentLength + { + unsigned int get() + { + return MaxExponentLengthValue; + } + } + + static property unsigned int MaxProgrammerBitLength + { + unsigned int get() + { + return MaxProgrammerBitLengthValue; + } + } - private: - static int ClipboardTextFormat(); static Platform::String - ^ ValidatePasteExpression(Platform::String ^ pastedText, CalculatorApp::Common::ViewMode mode, int programmerNumberBase, int bitLengthType); + ^ ValidatePasteExpression( + Platform::String ^ pastedText, + CalculatorApp::Common::ViewMode mode, + CalculatorApp::Common::NumberBase programmerNumberBase, + CalculatorApp::Common::BitLength bitLengthType); static Platform::String ^ ValidatePasteExpression( Platform::String ^ pastedText, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase, - int bitLengthType); - - static std::vector - ExtractOperands(const std::wstring& pasteExpression, CalculatorApp::Common::ViewMode mode); + CalculatorApp::Common::NumberBase programmerNumberBase, + CalculatorApp::Common::BitLength bitLengthType); + static CopyPasteMaxOperandLengthAndValue GetMaxOperandLengthAndValue( + CalculatorApp::Common::ViewMode mode, + CalculatorApp::Common::CategoryGroupType modeType, + CalculatorApp::Common::NumberBase programmerNumberBase, + CalculatorApp::Common::BitLength bitLengthType); + static Windows::Foundation::Collections::IVector< + Platform::String ^> ^ ExtractOperands(Platform::String ^ pasteExpression, CalculatorApp::Common::ViewMode mode); static bool ExpressionRegExMatch( - std::vector operands, + Windows::Foundation::Collections::IVector ^ operands, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1, - int bitLengthType = -1); - - static std::pair GetMaxOperandLengthAndValue( + CalculatorApp::Common::NumberBase programmerNumberBase, + CalculatorApp::Common::BitLength bitLengthType); + static Platform::String ^ SanitizeOperand(Platform::String ^ operand); + static Platform::String ^ RemoveUnwantedCharsFromString(Platform::String ^ input); + static Platform::IBox ^ TryOperandToULL(Platform::String ^ operand, CalculatorApp::Common::NumberBase numberBase); + static ULONG32 StandardScientificOperandLength(Platform::String ^ operand); + static ULONG32 OperandLength( + Platform::String ^ operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1, - int bitLengthType = -1); - static std::wstring SanitizeOperand(const std::wstring& operand); - static bool TryOperandToULL(const std::wstring& operand, int numberBase, unsigned long long int& result); - static size_t OperandLength( - const std::wstring& operand, - CalculatorApp::Common::ViewMode mode, - CalculatorApp::Common::CategoryGroupType modeType, - int programmerNumberBase = -1); - static size_t StandardScientificOperandLength(const std::wstring& operand); - static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase); - static std::wstring RemoveUnwantedCharsFromWstring(const std::wstring& input); + CalculatorApp::Common::NumberBase programmerNumberBase); + static ULONG32 ProgrammerOperandLength(Platform::String ^ operand, CalculatorApp::Common::NumberBase numberBase); - static constexpr size_t MaxStandardOperandLength = 16; - static constexpr size_t MaxScientificOperandLength = 32; - static constexpr size_t MaxConverterInputLength = 16; - static constexpr size_t MaxOperandCount = 100; - static constexpr size_t MaxPasteableLength = 512; - static constexpr size_t MaxExponentLength = 4; - static constexpr size_t MaxProgrammerBitLength = 64; - - static Platform::String ^ supportedFormats[]; - - friend class CalculatorUnitTests::CopyPasteManagerTest; + private: + static constexpr size_t MaxStandardOperandLengthValue = 16; + static constexpr size_t MaxScientificOperandLengthValue = 32; + static constexpr size_t MaxConverterInputLengthValue = 16; + static constexpr size_t MaxOperandCountValue = 100; + static constexpr size_t MaxExponentLengthValue = 4; + static constexpr size_t MaxProgrammerBitLengthValue = 64; + static constexpr size_t MaxPasteableLengthValue = 512; }; } diff --git a/src/CalcViewModel/Common/DateCalculator.cpp b/src/CalcViewModel/Common/DateCalculator.cpp index 19d3c492..35df7231 100644 --- a/src/CalcViewModel/Common/DateCalculator.cpp +++ b/src/CalcViewModel/Common/DateCalculator.cpp @@ -9,6 +9,11 @@ using namespace Windows::Foundation; using namespace Windows::Globalization; using namespace CalculatorApp::Common::DateCalculation; +bool operator==(const DateDifference& l, const DateDifference& r) +{ + return l.year == r.year && l.month == r.month && l.week == r.week && l.day == r.day; +} + DateCalculationEngine::DateCalculationEngine(_In_ String ^ calendarIdentifier) { m_calendar = ref new Calendar(); @@ -18,10 +23,9 @@ DateCalculationEngine::DateCalculationEngine(_In_ String ^ calendarIdentifier) // Adding Duration to a Date // Returns: True if function succeeds to calculate the date else returns False -bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime* endDate) +IBox ^ DateCalculationEngine::AddDuration(DateTime startDate, DateDifference duration) { auto currentCalendarSystem = m_calendar->GetCalendarSystem(); - try { m_calendar->SetDateTime(startDate); @@ -50,7 +54,8 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date m_calendar->AddDays(duration.day); } - *endDate = m_calendar->GetDateTime(); + m_calendar->ChangeCalendarSystem(currentCalendarSystem); + return m_calendar->GetDateTime(); } catch (Platform::InvalidArgumentException ^ ex) { @@ -58,17 +63,13 @@ bool DateCalculationEngine::AddDuration(_In_ DateTime startDate, _In_ const Date m_calendar->ChangeCalendarSystem(currentCalendarSystem); // Do nothing - return false; + return nullptr; } - - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - return true; } // Subtracting Duration from a Date // Returns: True if function succeeds to calculate the date else returns False -bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const DateDifference& duration, _Out_ DateTime* endDate) +IBox ^ DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ DateDifference duration) { auto currentCalendarSystem = m_calendar->GetCalendarSystem(); @@ -101,7 +102,18 @@ bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const { m_calendar->AddYears(-duration.year); } - *endDate = m_calendar->GetDateTime(); + m_calendar->ChangeCalendarSystem(currentCalendarSystem); + + auto dateTime = m_calendar->GetDateTime(); + // Check that the UniversalTime value is not negative + if (dateTime.UniversalTime >= 0) + { + return dateTime; + } + else + { + return nullptr; + } } catch (Platform::InvalidArgumentException ^ ex) { @@ -109,17 +121,12 @@ bool DateCalculationEngine::SubtractDuration(_In_ DateTime startDate, _In_ const m_calendar->ChangeCalendarSystem(currentCalendarSystem); // Do nothing - return false; + return nullptr; } - - m_calendar->ChangeCalendarSystem(currentCalendarSystem); - - // Check that the UniversalTime value is not negative - return (endDate->UniversalTime >= 0); } // Calculate the difference between two dates -bool DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateTime date2, _In_ DateUnit outputFormat, _Out_ DateDifference* difference) +IBox ^ DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateTime date2, _In_ DateUnit outputFormat) { DateTime startDate; DateTime endDate; @@ -177,8 +184,7 @@ bool DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateT { // Operation failed due to out of bound result // For example: 31st Dec, 9999 - last valid date - *difference = DateDifferenceUnknown; - return false; + return nullptr; } } @@ -194,8 +200,7 @@ bool DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateT if (differenceInDates[unitIndex] == 0) { // differenceInDates[unitIndex] is unsigned, the value can't be negative - *difference = DateDifferenceUnknown; - return false; + return nullptr; } differenceInDates[unitIndex] -= 1; pivotDate = tempPivotDate; @@ -220,8 +225,7 @@ bool DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateT { // Operation failed due to out of bound result // For example: 31st Dec, 9999 - last valid date - *difference = DateDifferenceUnknown; - return false; + return nullptr; } } } while (tempDaysDiff != 0); // dates are the same - exit the loop @@ -232,8 +236,7 @@ bool DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateT if (signedDaysDiff < 0) { // daysDiff is unsigned, the value can't be negative - *difference = DateDifferenceUnknown; - return false; + return nullptr; } daysDiff = signedDaysDiff; @@ -244,11 +247,12 @@ bool DateCalculationEngine::TryGetDateDifference(_In_ DateTime date1, _In_ DateT differenceInDates[3] = daysDiff; - difference->year = differenceInDates[0]; - difference->month = differenceInDates[1]; - difference->week = differenceInDates[2]; - difference->day = differenceInDates[3]; - return true; + DateDifference result; + result.year = differenceInDates[0]; + result.month = differenceInDates[1]; + result.week = differenceInDates[2]; + result.day = differenceInDates[3]; + return result; } // Private Methods diff --git a/src/CalcViewModel/Common/DateCalculator.h b/src/CalcViewModel/Common/DateCalculator.h index fdd885e7..7c9b6c4d 100644 --- a/src/CalcViewModel/Common/DateCalculator.h +++ b/src/CalcViewModel/Common/DateCalculator.h @@ -29,39 +29,30 @@ namespace CalculatorApp }; // Struct to store the difference between two Dates in the form of Years, Months , Weeks - struct DateDifference + public + value struct DateDifference { - int year = 0; - int month = 0; - int week = 0; - int day = 0; - - bool operator==(const DateDifference& dd) const - { - return year == dd.year && month == dd.month && week == dd.week && day == day; - } + int year; + int month; + int week; + int day; }; const DateDifference DateDifferenceUnknown{ INT_MIN, INT_MIN, INT_MIN, INT_MIN }; - class DateCalculationEngine + public + ref class DateCalculationEngine sealed { public: // Constructor DateCalculationEngine(_In_ Platform::String ^ calendarIdentifier); // Public Methods - bool __nothrow - AddDuration(_In_ Windows::Foundation::DateTime startDate, _In_ const DateDifference& duration, _Out_ Windows::Foundation::DateTime* endDate); - bool __nothrow SubtractDuration( - _In_ Windows::Foundation::DateTime startDate, - _In_ const DateDifference& duration, - _Out_ Windows::Foundation::DateTime* endDate); - bool __nothrow TryGetDateDifference( - _In_ Windows::Foundation::DateTime date1, - _In_ Windows::Foundation::DateTime date2, - _In_ DateUnit outputFormat, - _Out_ DateDifference* difference); + + Platform::IBox ^ AddDuration(_In_ Windows::Foundation::DateTime startDate, _In_ DateDifference duration); + Platform::IBox ^ SubtractDuration(_In_ Windows::Foundation::DateTime startDate, _In_ DateDifference duration); + Platform::IBox< + DateDifference> ^ TryGetDateDifference(_In_ Windows::Foundation::DateTime date1, _In_ Windows::Foundation::DateTime date2, _In_ DateUnit outputFormat); private: // Private Variables @@ -76,3 +67,5 @@ namespace CalculatorApp } } } + +bool operator==(const CalculatorApp::Common::DateCalculation::DateDifference& l, const CalculatorApp::Common::DateCalculation::DateDifference& r); diff --git a/src/CalcViewModel/Common/EngineResourceProvider.cpp b/src/CalcViewModel/Common/EngineResourceProvider.cpp index b65a2a31..05faff9f 100644 --- a/src/CalcViewModel/Common/EngineResourceProvider.cpp +++ b/src/CalcViewModel/Common/EngineResourceProvider.cpp @@ -17,7 +17,7 @@ namespace CalculatorApp m_resLoader = ResourceLoader::GetForViewIndependentUse("CEngineStrings"); } - wstring EngineResourceProvider::GetCEngineString(const wstring& id) + wstring EngineResourceProvider::GetCEngineString(wstring_view id) { const auto& localizationSettings = LocalizationSettings::GetInstance(); @@ -43,7 +43,7 @@ namespace CalculatorApp return numberGroupingString; } - StringReference idRef(id.c_str()); + StringReference idRef(id.data(), id.length()); String ^ str = m_resLoader->GetString(idRef); return str->Begin(); } diff --git a/src/CalcViewModel/Common/EngineResourceProvider.h b/src/CalcViewModel/Common/EngineResourceProvider.h index 8b5bb479..f4620c5c 100644 --- a/src/CalcViewModel/Common/EngineResourceProvider.h +++ b/src/CalcViewModel/Common/EngineResourceProvider.h @@ -11,7 +11,7 @@ namespace CalculatorApp { public: EngineResourceProvider(); - virtual std::wstring GetCEngineString(const std::wstring& id) override; + virtual std::wstring GetCEngineString(std::wstring_view id) override; private: Windows::ApplicationModel::Resources::ResourceLoader ^ m_resLoader; diff --git a/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp b/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp index e927b262..509a1659 100644 --- a/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp +++ b/src/CalcViewModel/Common/ExpressionCommandDeserializer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -47,13 +47,13 @@ COpndCommand CommandDeserializer::DeserializeOperand() bool fDecimal = m_dataReader->ReadBoolean(); bool fSciFmt = m_dataReader->ReadBoolean(); - std::shared_ptr> cmdVector = std::make_shared>(); + std::shared_ptr> cmdVector = std::make_shared>(); auto cmdVectorSize = m_dataReader->ReadUInt32(); for (unsigned int j = 0; j < cmdVectorSize; ++j) { int eachOpndcmd = m_dataReader->ReadInt32(); - cmdVector->Append(eachOpndcmd); + cmdVector->push_back(eachOpndcmd); } return COpndCommand(cmdVector, fNegative, fDecimal, fSciFmt); @@ -68,7 +68,6 @@ CParentheses CommandDeserializer::DeserializeParentheses() CUnaryCommand CommandDeserializer::DeserializeUnary() { auto cmdSize = m_dataReader->ReadUInt32(); - std::shared_ptr> cmdVector = std::make_shared>(); if (cmdSize == 1) { diff --git a/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp b/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp index bbf9e183..fb0cd83a 100644 --- a/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp +++ b/src/CalcViewModel/Common/ExpressionCommandSerializer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -18,28 +18,22 @@ void SerializeCommandVisitor::Visit(_In_ COpndCommand& opndCmd) m_dataWriter->WriteBoolean(opndCmd.IsDecimalPresent()); m_dataWriter->WriteBoolean(opndCmd.IsSciFmt()); - auto opndCmds = opndCmd.GetCommands(); - unsigned int opndCmdSize; - opndCmds->GetSize(&opndCmdSize); + const auto& opndCmds = opndCmd.GetCommands(); + unsigned int opndCmdSize = static_cast(opndCmds->size()); m_dataWriter->WriteUInt32(opndCmdSize); - for (unsigned int j = 0; j < opndCmdSize; ++j) + for (int eachOpndcmd : *opndCmds) { - int eachOpndcmd; - opndCmds->GetAt(j, &eachOpndcmd); m_dataWriter->WriteInt32(eachOpndcmd); } } void SerializeCommandVisitor::Visit(_In_ CUnaryCommand& unaryCmd) { - auto cmds = unaryCmd.GetCommands(); - unsigned int cmdSize; - cmds->GetSize(&cmdSize); + const auto& cmds = unaryCmd.GetCommands(); + unsigned int cmdSize = static_cast(cmds->size()); m_dataWriter->WriteUInt32(cmdSize); - for (unsigned int j = 0; j < cmdSize; ++j) + for (int eachOpndcmd : *cmds) { - int eachOpndcmd; - cmds->GetAt(j, &eachOpndcmd); m_dataWriter->WriteInt32(eachOpndcmd); } } diff --git a/src/CalcViewModel/Common/KeyboardShortcutManager.cpp b/src/CalcViewModel/Common/KeyboardShortcutManager.cpp index 8b2ca30a..8990d5e8 100644 --- a/src/CalcViewModel/Common/KeyboardShortcutManager.cpp +++ b/src/CalcViewModel/Common/KeyboardShortcutManager.cpp @@ -519,7 +519,7 @@ void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow ^ sender, KeyEventArgs auto navView = buttons.first->second.Resolve(); auto appViewModel = safe_cast(navView->DataContext); appViewModel->Mode = ViewMode::Date; - auto categoryName = AppResourceProvider::GetInstance().GetResourceString(L"DateCalculationModeText"); + auto categoryName = AppResourceProvider::GetInstance()->GetResourceString(L"DateCalculationModeText"); appViewModel->CategoryName = categoryName; auto menuItems = static_cast ^>(navView->MenuItemsSource); diff --git a/src/CalcViewModel/Common/LocalizationService.cpp b/src/CalcViewModel/Common/LocalizationService.cpp index eacc04de..9060b04a 100644 --- a/src/CalcViewModel/Common/LocalizationService.cpp +++ b/src/CalcViewModel/Common/LocalizationService.cpp @@ -94,16 +94,16 @@ LocalizationService::LocalizationService(_In_ const wchar_t * const overridedLan m_locale = locale(""); } auto resourceLoader = AppResourceProvider::GetInstance(); - m_fontFamilyOverride = resourceLoader.GetResourceString(L"LocalizedFontFamilyOverride"); + m_fontFamilyOverride = resourceLoader->GetResourceString(L"LocalizedFontFamilyOverride"); String ^ reserved = L"RESERVED_FOR_FONTLOC"; m_overrideFontApiValues = ((m_fontFamilyOverride != nullptr) && (m_fontFamilyOverride != reserved)); if (m_overrideFontApiValues) { - String ^ localizedUICaptionFontSizeFactorOverride = resourceLoader.GetResourceString(L"LocalizedUICaptionFontSizeFactorOverride"); - String ^ localizedUITextFontSizeFactorOverride = resourceLoader.GetResourceString(L"LocalizedUITextFontSizeFactorOverride"); - String ^ localizedFontWeightOverride = resourceLoader.GetResourceString(L"LocalizedFontWeightOverride"); + String ^ localizedUICaptionFontSizeFactorOverride = resourceLoader->GetResourceString(L"LocalizedUICaptionFontSizeFactorOverride"); + String ^ localizedUITextFontSizeFactorOverride = resourceLoader->GetResourceString(L"LocalizedUITextFontSizeFactorOverride"); + String ^ localizedFontWeightOverride = resourceLoader->GetResourceString(L"LocalizedFontWeightOverride"); // If any of the font overrides are modified then all of them need to be modified assert(localizedFontWeightOverride != reserved); @@ -503,16 +503,49 @@ unordered_map LocalizationService::GetTokenToReadableNameMap() make_pair(L"27", L"HyperbolicTangent"), make_pair(L"87", L"InverseHyperbolicTangent"), + // Secant permutations + make_pair(L"SecDeg", L"SecantDegrees"), + make_pair(L"SecRad", L"SecantRadians"), + make_pair(L"SecGrad", L"SecantGradians"), + make_pair(L"InverseSecDeg", L"InverseSecantDegrees"), + make_pair(L"InverseSecRad", L"InverseSecantRadians"), + make_pair(L"InverseSecGrad", L"InverseSecantGradians"), + make_pair(L"Sech", L"HyperbolicSecant"), + make_pair(L"InverseSech", L"InverseHyperbolicSecant"), + + // Cosecant permutations + make_pair(L"CscDeg", L"CosecantDegrees"), + make_pair(L"CscRad", L"CosecantRadians"), + make_pair(L"CscGrad", L"CosecantGradians"), + make_pair(L"InverseCscDeg", L"InverseCosecantDegrees"), + make_pair(L"InverseCscRad", L"InverseCosecantRadians"), + make_pair(L"InverseCscGrad", L"InverseCosecantGradians"), + make_pair(L"Csch", L"HyperbolicCosecant"), + make_pair(L"InverseCsch", L"InverseHyperbolicCosecant"), + + // Cotangent permutations + make_pair(L"CotDeg", L"CotangentDegrees"), + make_pair(L"CotRad", L"CotangentRadians"), + make_pair(L"CotGrad", L"CotangentGradians"), + make_pair(L"InverseCotDeg", L"InverseCotangentDegrees"), + make_pair(L"InverseCotRad", L"InverseCotangentRadians"), + make_pair(L"InverseCotGrad", L"InverseCotangentGradians"), + make_pair(L"Coth", L"HyperbolicCotangent"), + make_pair(L"InverseCoth", L"InverseHyperbolicCotangent"), + // Miscellaneous Scientific functions make_pair(L"94", L"Factorial"), make_pair(L"35", L"DegreeMinuteSecond"), make_pair(L"28", L"NaturalLog"), - make_pair(L"91", L"Square") + make_pair(L"91", L"Square"), + make_pair(L"CubeRoot", L"CubeRoot"), + make_pair(L"Abs", L"AbsoluteValue") }; static vector> s_noParenEngineKeyResourceMap = { // Programmer mode functions make_pair(L"9", L"LeftShift"), make_pair(L"10", L"RightShift"), + make_pair(L"LogBaseX", L"Logx"), // Y Root scientific function make_pair(L"16", L"YRoot") @@ -521,12 +554,12 @@ unordered_map LocalizationService::GetTokenToReadableNameMap() unordered_map tokenToReadableNameMap{}; auto resProvider = AppResourceProvider::GetInstance(); - static const wstring openParen = resProvider.GetCEngineString(StringReference(s_openParenResourceKey))->Data(); + static const wstring openParen = resProvider->GetCEngineString(StringReference(s_openParenResourceKey))->Data(); for (const auto& keyPair : s_parenEngineKeyResourceMap) { - wstring engineStr = resProvider.GetCEngineString(StringReference(keyPair.first.c_str()))->Data(); - wstring automationName = resProvider.GetResourceString(StringReference(keyPair.second.c_str()))->Data(); + wstring engineStr = resProvider->GetCEngineString(StringReference(keyPair.first.c_str()))->Data(); + wstring automationName = resProvider->GetResourceString(StringReference(keyPair.second.c_str()))->Data(); tokenToReadableNameMap.emplace(engineStr + openParen, automationName); } @@ -534,15 +567,15 @@ unordered_map LocalizationService::GetTokenToReadableNameMap() for (const auto& keyPair : s_noParenEngineKeyResourceMap) { - wstring engineStr = resProvider.GetCEngineString(StringReference(keyPair.first.c_str()))->Data(); - wstring automationName = resProvider.GetResourceString(StringReference(keyPair.second.c_str()))->Data(); + wstring engineStr = resProvider->GetCEngineString(StringReference(keyPair.first.c_str()))->Data(); + wstring automationName = resProvider->GetResourceString(StringReference(keyPair.second.c_str()))->Data(); tokenToReadableNameMap.emplace(engineStr, automationName); } s_noParenEngineKeyResourceMap.clear(); // Also replace hyphens with "minus" - wstring minusText = resProvider.GetResourceString(L"minus")->Data(); + wstring minusText = resProvider->GetResourceString(L"minus")->Data(); tokenToReadableNameMap.emplace(L"-", minusText); return tokenToReadableNameMap; @@ -559,23 +592,22 @@ String ^ LocalizationService::GetNarratorReadableToken(String ^ rawToken) } else { - static const String ^ openParen = AppResourceProvider::GetInstance().GetCEngineString(StringReference(s_openParenResourceKey)); + static const String ^ openParen = AppResourceProvider::GetInstance()->GetCEngineString(StringReference(s_openParenResourceKey)); return ref new String(itr->second.c_str()) + L" " + openParen; } } String ^ LocalizationService::GetNarratorReadableString(String ^ rawString) { - wstringstream readableString{}; - readableString << L""; + wstring readableString{}; wstring asWstring = rawString->Data(); for (const auto& c : asWstring) { - readableString << LocalizationService::GetNarratorReadableToken(L"" + c)->Data(); + readableString += LocalizationService::GetNarratorReadableToken(ref new String(&c, 1))->Data(); } - return ref new String(readableString.str().c_str()); + return ref new String(readableString.c_str()); } void LocalizationService::Sort(std::vector& source) diff --git a/src/CalcViewModel/Common/LocalizationService.h b/src/CalcViewModel/Common/LocalizationService.h index 6c5d0c51..d6921371 100644 --- a/src/CalcViewModel/Common/LocalizationService.h +++ b/src/CalcViewModel/Common/LocalizationService.h @@ -58,10 +58,11 @@ namespace CalculatorApp Windows::Globalization::NumberFormatting::DecimalFormatter ^ GetRegionalSettingsAwareDecimalFormatter() const; Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ GetRegionalSettingsAwareDateTimeFormatter(_In_ Platform::String ^ format) const; - Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ GetRegionalSettingsAwareDateTimeFormatter( - _In_ Platform::String ^ format, - _In_ Platform::String ^ calendarIdentifier, - _In_ Platform::String ^ clockIdentifier) const; + Windows::Globalization::DateTimeFormatting::DateTimeFormatter + ^ GetRegionalSettingsAwareDateTimeFormatter( + _In_ Platform::String ^ format, + _In_ Platform::String ^ calendarIdentifier, + _In_ Platform::String ^ clockIdentifier) const; Windows::Globalization::NumberFormatting::CurrencyFormatter ^ GetRegionalSettingsAwareCurrencyFormatter() const; diff --git a/src/CalcViewModel/Common/LocalizationSettings.h b/src/CalcViewModel/Common/LocalizationSettings.h index addc0c39..86d45ab2 100644 --- a/src/CalcViewModel/Common/LocalizationSettings.h +++ b/src/CalcViewModel/Common/LocalizationSettings.h @@ -14,45 +14,48 @@ namespace CalculatorApp { private: LocalizationSettings() - { - int result = 0; - // Use DecimalFormatter as it respects the locale and the user setting - Windows::Globalization::NumberFormatting::DecimalFormatter ^ formatter; - formatter = LocalizationService::GetInstance()->GetRegionalSettingsAwareDecimalFormatter(); + : LocalizationSettings(LocalizationService::GetInstance()->GetRegionalSettingsAwareDecimalFormatter()) + { + } + + public: + // This is only public for unit testing purposes. + LocalizationSettings(Windows::Globalization::NumberFormatting::DecimalFormatter ^ formatter) + { formatter->FractionDigits = 0; formatter->IsDecimalPointAlwaysDisplayed = false; - for (unsigned int i = 0; i < 10; i++) + for (unsigned int i = 0; i < m_digitSymbols.size(); i++) { - m_digitSymbols.at(i) = formatter->FormatUInt(i)->Data()[0]; + m_digitSymbols[i] = formatter->FormatUInt(i)->Data()[0]; } wchar_t resolvedName[LOCALE_NAME_MAX_LENGTH]; - result = ResolveLocaleName(formatter->ResolvedLanguage->Data(), resolvedName, LOCALE_NAME_MAX_LENGTH); + int result = ResolveLocaleName(formatter->ResolvedLanguage->Data(), resolvedName, LOCALE_NAME_MAX_LENGTH); if (result == 0) { throw std::runtime_error("Unexpected error resolving locale name"); } else { - m_resolvedName = resolvedName; + m_resolvedName = ref new Platform::String(resolvedName); wchar_t decimalString[LocaleSettingBufferSize] = L""; - result = GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_SDECIMAL, decimalString, static_cast(std::size(decimalString))); + result = GetLocaleInfoEx(m_resolvedName->Data(), LOCALE_SDECIMAL, decimalString, static_cast(std::size(decimalString))); if (result == 0) { throw std::runtime_error("Unexpected error while getting locale info"); } wchar_t groupingSymbolString[LocaleSettingBufferSize] = L""; - result = GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_STHOUSAND, groupingSymbolString, static_cast(std::size(groupingSymbolString))); + result = GetLocaleInfoEx(m_resolvedName->Data(), LOCALE_STHOUSAND, groupingSymbolString, static_cast(std::size(groupingSymbolString))); if (result == 0) { throw std::runtime_error("Unexpected error while getting locale info"); } wchar_t numberGroupingString[LocaleSettingBufferSize] = L""; - result = GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_SGROUPING, numberGroupingString, static_cast(std::size(numberGroupingString))); + result = GetLocaleInfoEx(m_resolvedName->Data(), LOCALE_SGROUPING, numberGroupingString, static_cast(std::size(numberGroupingString))); if (result == 0) { throw std::runtime_error("Unexpected error while getting locale info"); @@ -61,7 +64,7 @@ namespace CalculatorApp // Get locale info for List Separator, eg. comma is used in many locales wchar_t listSeparatorString[4] = L""; result = ::GetLocaleInfoEx( - m_resolvedName.c_str(), + m_resolvedName->Data(), LOCALE_SLIST, listSeparatorString, static_cast(std::size(listSeparatorString))); // Max length of the expected return value is 4 @@ -72,7 +75,7 @@ namespace CalculatorApp int currencyTrailingDigits = 0; result = GetLocaleInfoEx( - m_resolvedName.c_str(), + m_resolvedName->Data(), LOCALE_ICURRDIGITS | LOCALE_RETURN_NUMBER, (LPWSTR)¤cyTrailingDigits, sizeof(currencyTrailingDigits) / sizeof(WCHAR)); @@ -85,7 +88,7 @@ namespace CalculatorApp // A value of 0 indicates the symbol follows the currency value. int currencySymbolPrecedence = 1; result = GetLocaleInfoEx( - m_resolvedName.c_str(), + m_resolvedName->Data(), LOCALE_IPOSSYMPRECEDES | LOCALE_RETURN_NUMBER, (LPWSTR)¤cySymbolPrecedence, sizeof(currencySymbolPrecedence) / sizeof(WCHAR)); @@ -104,14 +107,14 @@ namespace CalculatorApp // Note: This function returns 0 on failure. // We'll ignore the failure in that case and the CalendarIdentifier would get set to GregorianCalendar. CALID calId; - ::GetLocaleInfoEx(m_resolvedName.c_str(), LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER, reinterpret_cast(&calId), sizeof(calId)); + ::GetLocaleInfoEx(m_resolvedName->Data(), LOCALE_ICALENDARTYPE | LOCALE_RETURN_NUMBER, reinterpret_cast(&calId), sizeof(calId)); m_calendarIdentifier = GetCalendarIdentifierFromCalid(calId); // Get FirstDayOfWeek Date and Time setting wchar_t day[80] = L""; ::GetLocaleInfoEx( - m_resolvedName.c_str(), + m_resolvedName->Data(), LOCALE_IFIRSTDAYOFWEEK, // The first day in a week reinterpret_cast(day), // Argument is of type PWSTR static_cast(std::size(day))); // Max return size are 80 characters @@ -122,7 +125,6 @@ namespace CalculatorApp m_firstDayOfWeek = static_cast((_wtoi(day) + 1) % 7); // static cast int to DayOfWeek enum } - public: // A LocalizationSettings object is not copyable. LocalizationSettings(const LocalizationSettings&) = delete; LocalizationSettings& operator=(const LocalizationSettings&) = delete; @@ -141,16 +143,12 @@ namespace CalculatorApp Platform::String ^ GetLocaleName() const { - return ref new Platform::String(m_resolvedName.c_str()); + return m_resolvedName; } bool IsDigitEnUsSetting() const { - if (this->GetDigitSymbolFromEnUsDigit('0') == L'0') - { - return true; - } - return false; + return (this->GetDigitSymbolFromEnUsDigit('0') == L'0'); } void LocalizeDisplayValue(_Inout_ std::wstring* stringToLocalize) const @@ -169,62 +167,46 @@ namespace CalculatorApp } } - Platform::String ^ GetEnglishValueFromLocalizedDigits(const std::wstring& localizedString) const + Platform::String ^ GetEnglishValueFromLocalizedDigits(Platform::String ^ localizedString) const { if (m_resolvedName == L"en-US") { - return ref new Platform::String(localizedString.c_str()); + return localizedString; } - size_t i = 0; - size_t length = localizedString.size(); - std::unique_ptr englishString(new wchar_t[length + 1]); // +1 for the null termination + std::wstring englishString; + englishString.reserve(localizedString->Length()); - for (; i < length; ++i) + for (wchar_t ch : localizedString) { - wchar_t ch = localizedString[i]; if (!IsEnUsDigit(ch)) { - for (int j = 0; j < 10; ++j) + auto it = std::find(m_digitSymbols.begin(), m_digitSymbols.end(), ch); + + if (it != m_digitSymbols.end()) { - if (ch == m_digitSymbols[j]) - { - ch = j.ToString()->Data()[0]; - break; - // ch = val - L'0'; - } + auto index = std::distance(m_digitSymbols.begin(), it); + ch = index.ToString()->Data()[0]; } } if (ch == m_decimalSeparator) { ch = L'.'; } - englishString[i] = ch; + englishString += ch; } - englishString[i] = '\0'; - return ref new Platform::String(englishString.get()); + return ref new Platform::String(englishString.c_str()); } bool IsEnUsDigit(const wchar_t digit) const { - if (digit >= L'0' && digit <= L'9') - { - return true; - } - return false; + return (digit >= L'0' && digit <= L'9'); } bool IsLocalizedDigit(const wchar_t digit) const { - for (auto dig : m_digitSymbols) - { - if (digit == dig) - { - return true; - } - } - return false; + return std::find(m_digitSymbols.begin(), m_digitSymbols.end(), digit) != m_digitSymbols.end(); } bool IsLocalizedHexDigit(const wchar_t digit) const @@ -234,15 +216,7 @@ namespace CalculatorApp return true; } - for (auto dig : s_hexSymbols) - { - if (digit == dig) - { - return true; - } - } - - return false; + return std::find(s_hexSymbols.begin(), s_hexSymbols.end(), digit) != s_hexSymbols.end(); } wchar_t GetDigitSymbolFromEnUsDigit(wchar_t digitSymbol) const @@ -264,16 +238,12 @@ namespace CalculatorApp std::wstring GetDecimalSeparatorStr() const { - std::wstring result; - result.push_back(m_decimalSeparator); - return result; + return std::wstring(1, m_decimalSeparator); } std::wstring GetNumberGroupingSeparatorStr() const { - std::wstring result; - result.push_back(m_numberGroupSeparator); - return result; + return std::wstring(1, m_numberGroupSeparator); } std::wstring GetNumberGroupingStr() const @@ -281,18 +251,13 @@ namespace CalculatorApp return m_numberGrouping; } - void RemoveGroupSeparators(const wchar_t* value, const size_t length, std::wstring* rawValue) const + Platform::String ^ RemoveGroupSeparators(Platform::String ^ source) const { - rawValue->clear(); - rawValue->reserve(length); - - for (size_t i = 0; i < length; i++) - { - if (value[i] != L' ' && value[i] != m_numberGroupSeparator) - { - rawValue->append(1, value[i]); - } - } + std::wstring destination; + std::copy_if( + begin(source), end(source), std::back_inserter(destination), [this](auto const c) { return c != L' ' && c != m_numberGroupSeparator; }); + + return ref new Platform::String(destination.c_str()); } Platform::String ^ GetCalendarIdentifier() const @@ -371,7 +336,7 @@ namespace CalculatorApp Platform::String ^ m_calendarIdentifier; Windows::Globalization::DayOfWeek m_firstDayOfWeek; int m_currencySymbolPrecedence; - std::wstring m_resolvedName; + Platform::String ^ m_resolvedName; int m_currencyTrailingDigits; static const unsigned int LocaleSettingBufferSize = 16; }; diff --git a/src/CalcViewModel/Common/LocalizationStringUtil.h b/src/CalcViewModel/Common/LocalizationStringUtil.h index 1a360bdb..0e3d9dff 100644 --- a/src/CalcViewModel/Common/LocalizationStringUtil.h +++ b/src/CalcViewModel/Common/LocalizationStringUtil.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once @@ -9,50 +9,78 @@ namespace CalculatorApp { namespace Common { - class LocalizationStringUtil + class LocalizationStringUtilInternal { public: - static std::wstring GetLocalizedString(const wchar_t* pMessage, ...) + static Platform::String ^ GetLocalizedString(Platform::String ^ pMessage, ...) { std::wstring returnString = L""; const UINT32 length = 1024; std::unique_ptr spBuffer = std::unique_ptr(new wchar_t[length]); va_list args = NULL; va_start(args, pMessage); - DWORD fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING, pMessage, 0, 0, spBuffer.get(), length, &args); + DWORD fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING, pMessage->Data(), 0, 0, spBuffer.get(), length, &args); va_end(args); if (fmtReturnVal != 0) { - returnString = spBuffer.get(); + return ref new Platform::String(spBuffer.get()); } - - return returnString; - } - - template - static Platform::String^ GetLocalizedNarratorAnnouncement(Platform::String^ resourceKey, Platform::String^& formatVariable, T*... params) - { - EnsureInitialization(resourceKey, formatVariable); - return StringReference(GetLocalizedString(formatVariable->Data(), params...).c_str()); - } - - private: - static void EnsureInitialization(Platform::String^ resourceKey, Platform::String^& formatVariable) - { - if (resourceKey == nullptr || resourceKey->IsEmpty()) + else { - return; + return ref new Platform::String(); } - - // If the formatVariable already has a value, we don't need to set it again. Simply return. - if (formatVariable != nullptr && !formatVariable->IsEmpty()) - { - return; - } - - formatVariable = AppResourceProvider::GetInstance().GetResourceString(resourceKey); } }; + + public + ref class LocalizationStringUtil sealed + { + public: + static Platform::String + ^ GetLocalizedString(Platform::String ^ pMessage) + { + return LocalizationStringUtilInternal::GetLocalizedString(pMessage); + } + + static Platform::String + ^ GetLocalizedString( + Platform::String ^ pMessage, + Platform::String ^ param1) + { + return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data()); + } + + static Platform::String + ^ GetLocalizedString( + Platform::String ^ pMessage, + Platform::String ^ param1, + Platform::String ^ param2) + { + return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data(), param2->Data()); + } + + static Platform::String + ^ GetLocalizedString( + Platform::String ^ pMessage, + Platform::String ^ param1, + Platform::String ^ param2, + Platform::String + ^ param3) + { + return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data(), param2->Data(), param3->Data()); + } + + static Platform::String + ^ GetLocalizedString( + Platform::String ^ pMessage, + Platform::String ^ param1, + Platform::String ^ param2, + Platform::String ^ param3, + Platform::String ^ param4) + { + return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data(), param2->Data(), param3->Data(), param4->Data()); + } + }; } } diff --git a/src/CalcViewModel/Common/NavCategory.cpp b/src/CalcViewModel/Common/NavCategory.cpp index 9dfd905c..90f25c92 100644 --- a/src/CalcViewModel/Common/NavCategory.cpp +++ b/src/CalcViewModel/Common/NavCategory.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -160,7 +160,7 @@ static constexpr array s_categoryManifest = { L"\uE945", CategoryGroupType::Converter, MyVirtualKey::None, - POSITIVE_ONLY }, + SUPPORTS_NEGATIVE }, NavCategoryInitializer{ ViewMode::Data, DATA_ID, L"Data", @@ -184,7 +184,7 @@ static constexpr array s_categoryManifest = { L"\uF515", CategoryGroupType::Converter, MyVirtualKey::None, - POSITIVE_ONLY } }; + SUPPORTS_NEGATIVE } }; // This function should only be used when storing the mode to app data. int NavCategory::Serialize(ViewMode mode) @@ -368,33 +368,28 @@ NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupIniti m_GroupType = groupInitializer.type; auto resProvider = AppResourceProvider::GetInstance(); - String ^ headerResourceKey = StringReference(groupInitializer.headerResourceKey); - String ^ modeResourceKey = StringReference(groupInitializer.modeResourceKey); - String ^ automationResourceKey = StringReference(groupInitializer.automationResourceKey); - m_Name = resProvider.GetResourceString(headerResourceKey); - String ^ groupMode = resProvider.GetResourceString(modeResourceKey); - String ^ automationName = resProvider.GetResourceString(automationResourceKey); + m_Name = resProvider->GetResourceString(StringReference(groupInitializer.headerResourceKey)); + String ^ groupMode = resProvider->GetResourceString(StringReference(groupInitializer.modeResourceKey)); + String ^ automationName = resProvider->GetResourceString(StringReference(groupInitializer.automationResourceKey)); - String ^ navCategoryHeaderAutomationNameFormat = resProvider.GetResourceString(L"NavCategoryHeader_AutomationNameFormat"); - m_AutomationName = - ref new String(LocalizationStringUtil::GetLocalizedString(navCategoryHeaderAutomationNameFormat->Data(), automationName->Data()).c_str()); + String ^ navCategoryHeaderAutomationNameFormat = resProvider->GetResourceString(L"NavCategoryHeader_AutomationNameFormat"); + m_AutomationName = LocalizationStringUtil::GetLocalizedString(navCategoryHeaderAutomationNameFormat, automationName); - String ^ navCategoryItemAutomationNameFormat = resProvider.GetResourceString(L"NavCategoryItem_AutomationNameFormat"); + String ^ navCategoryItemAutomationNameFormat = resProvider->GetResourceString(L"NavCategoryItem_AutomationNameFormat"); for (const NavCategoryInitializer& categoryInitializer : s_categoryManifest) { if (categoryInitializer.groupType == groupInitializer.type) { String ^ nameResourceKey = StringReference(categoryInitializer.nameResourceKey); - String ^ categoryName = resProvider.GetResourceString(nameResourceKey + "Text"); - String ^ categoryAutomationName = ref new String( - LocalizationStringUtil::GetLocalizedString(navCategoryItemAutomationNameFormat->Data(), categoryName->Data(), m_Name->Data()).c_str()); + String ^ categoryName = resProvider->GetResourceString(nameResourceKey + "Text"); + String ^ categoryAutomationName = LocalizationStringUtil::GetLocalizedString(navCategoryItemAutomationNameFormat, categoryName, m_Name); m_Categories->Append(ref new NavCategory( categoryName, categoryAutomationName, StringReference(categoryInitializer.glyph), - resProvider.GetResourceString(nameResourceKey + "AccessKey"), + resProvider->GetResourceString(nameResourceKey + "AccessKey"), groupMode, categoryInitializer.viewMode, categoryInitializer.supportsNegative)); diff --git a/src/CalcViewModel/Common/NumberBase.h b/src/CalcViewModel/Common/NumberBase.h new file mode 100644 index 00000000..4e15efa1 --- /dev/null +++ b/src/CalcViewModel/Common/NumberBase.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +namespace CalculatorApp::Common +{ +public + enum class NumberBase + { + Unknown = -1, + HexBase = 5, + DecBase = 6, + OctBase = 7, + BinBase = 8 + }; +}; diff --git a/src/CalcViewModel/Common/TraceLogger.cpp b/src/CalcViewModel/Common/TraceLogger.cpp index 65375549..845b010b 100644 --- a/src/CalcViewModel/Common/TraceLogger.cpp +++ b/src/CalcViewModel/Common/TraceLogger.cpp @@ -10,6 +10,7 @@ using namespace CalculatorApp; using namespace CalculatorApp::Common; using namespace Concurrency; using namespace std; +using namespace Platform; using namespace winrt; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation::Diagnostics; @@ -57,47 +58,43 @@ namespace CalculatorApp TraceLogger::TraceLogger() : g_calculatorProvider( - L"MicrosoftCalculator", - LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), - GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 }) + L"MicrosoftCalculator", + LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), + GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 }) , // Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0} m_appLaunchActivity{ nullptr } { CoCreateGuid(&sessionGuid); } - TraceLogger::~TraceLogger() + TraceLogger ^ TraceLogger::GetInstance() { - } - - TraceLogger& TraceLogger::GetInstance() - { - static TraceLogger s_selfInstance; + static TraceLogger ^ s_selfInstance = ref new TraceLogger(); return s_selfInstance; } - bool TraceLogger::GetTraceLoggingProviderEnabled() const + bool TraceLogger::GetTraceLoggingProviderEnabled() { return g_calculatorProvider.Enabled(); } #pragma region Tracing methods - void TraceLogger::LogLevel1Event(wstring_view eventName, LoggingFields fields) const + void TraceLogger::LogLevel1Event(wstring_view eventName, LoggingFields fields) { g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_1)); } - void TraceLogger::LogLevel2Event(wstring_view eventName, LoggingFields fields) const + void TraceLogger::LogLevel2Event(wstring_view eventName, LoggingFields fields) { g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_2)); } - void TraceLogger::LogLevel3Event(wstring_view eventName, LoggingFields fields) const + void TraceLogger::LogLevel3Event(wstring_view eventName, LoggingFields fields) { g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_3)); } - unique_ptr TraceLogger::CreateTraceActivity(wstring_view eventName, LoggingFields fields) const + unique_ptr TraceLogger::CreateTraceActivity(wstring_view eventName, LoggingFields fields) { return make_unique(g_calculatorProvider, eventName, fields); } @@ -117,7 +114,7 @@ namespace CalculatorApp return true; } - void TraceLogger::LogVisualStateChanged(ViewMode mode, wstring_view state, bool isAlwaysOnTop) const + void TraceLogger::LogVisualStateChanged(ViewMode mode, String ^ state, bool isAlwaysOnTop) { if (!GetTraceLoggingProviderEnabled()) { @@ -127,7 +124,7 @@ namespace CalculatorApp LoggingFields fields{}; fields.AddGuid(L"SessionGuid", sessionGuid); fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"VisualState", state); + fields.AddString(L"VisualState", state->Data()); fields.AddBoolean(L"IsAlwaysOnTop", isAlwaysOnTop); fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); LogLevel2Event(EVENT_NAME_VISUAL_STATE_CHANGED, fields); @@ -152,7 +149,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_WINDOW_ON_CREATED, fields); } - void TraceLogger::LogModeChange(ViewMode mode) const + void TraceLogger::LogModeChange(ViewMode mode) { if (!GetTraceLoggingProviderEnabled()) return; @@ -167,7 +164,7 @@ namespace CalculatorApp } } - void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex) const + void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex) { if (!GetTraceLoggingProviderEnabled()) { @@ -183,7 +180,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_HISTORY_ITEM_LOAD, fields); } - void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex) const + void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex) { if (!GetTraceLoggingProviderEnabled()) { @@ -199,7 +196,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_MEMORY_ITEM_LOAD, fields); } - void TraceLogger::LogError(ViewMode mode, wstring_view functionName, wstring_view errorString) + void TraceLogger::LogError(ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString) { if (!GetTraceLoggingProviderEnabled()) return; @@ -207,13 +204,13 @@ namespace CalculatorApp LoggingFields fields{}; fields.AddGuid(L"SessionGuid", sessionGuid); fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"FunctionName", functionName); - fields.AddString(L"Message", errorString); + fields.AddString(L"FunctionName", functionName->Data()); + fields.AddString(L"Message", errorString->Data()); fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); LogLevel2Event(EVENT_NAME_EXCEPTION, fields); } - void TraceLogger::LogStandardException(ViewMode mode, wstring_view functionName, const exception& e) const + void TraceLogger::LogStandardException(ViewMode mode, wstring_view functionName, const exception& e) { if (!GetTraceLoggingProviderEnabled()) return; @@ -229,7 +226,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_EXCEPTION, fields); } - void TraceLogger::LogWinRTException(ViewMode mode, wstring_view functionName, hresult_error const& e) const + void TraceLogger::LogWinRTException(ViewMode mode, wstring_view functionName, hresult_error const& e) { if (!GetTraceLoggingProviderEnabled()) return; @@ -244,7 +241,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_EXCEPTION, fields); } - void TraceLogger::LogPlatformException(ViewMode mode, wstring_view functionName, Platform::Exception ^ e) const + void TraceLogger::LogPlatformException(ViewMode mode, wstring_view functionName, Platform::Exception ^ e) { if (!GetTraceLoggingProviderEnabled()) return; @@ -291,7 +288,7 @@ namespace CalculatorApp } } - void TraceLogger::UpdateWindowCount(size_t windowCount) + void TraceLogger::UpdateWindowCount(uint64 windowCount) { if (windowCount == 0) { @@ -301,6 +298,11 @@ namespace CalculatorApp currentWindowCount = windowCount; } + void TraceLogger::DecreaseWindowCount() + { + currentWindowCount = 0; + } + void TraceLogger::LogButtonUsage() { if (!GetTraceLoggingProviderEnabled()) @@ -348,7 +350,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_DATE_CALCULATION_MODE_USED, fields); } - void TraceLogger::LogConverterInputReceived(ViewMode mode) const + void TraceLogger::LogConverterInputReceived(ViewMode mode) { if (!GetTraceLoggingProviderEnabled()) return; @@ -360,7 +362,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_CONVERTER_INPUT_RECEIVED, fields); } - void TraceLogger::LogNavBarOpened() const + void TraceLogger::LogNavBarOpened() { if (!GetTraceLoggingProviderEnabled()) return; @@ -371,7 +373,7 @@ namespace CalculatorApp LogLevel2Event(EVENT_NAME_NAV_BAR_OPENED, fields); } - void TraceLogger::LogInputPasted(ViewMode mode) const + void TraceLogger::LogInputPasted(ViewMode mode) { if (!GetTraceLoggingProviderEnabled()) return; diff --git a/src/CalcViewModel/Common/TraceLogger.h b/src/CalcViewModel/Common/TraceLogger.h index d8a4289e..fa24f8e0 100644 --- a/src/CalcViewModel/Common/TraceLogger.h +++ b/src/CalcViewModel/Common/TraceLogger.h @@ -28,33 +28,31 @@ namespace CalculatorApp } }; - class TraceLogger +public + ref class TraceLogger sealed { public: - TraceLogger(_In_ TraceLogger const&) = delete; - TraceLogger const& operator=(_In_ TraceLogger const&) = delete; - ~TraceLogger(); - static TraceLogger& GetInstance(); - bool GetTraceLoggingProviderEnabled() const; - - void LogModeChange(CalculatorApp::Common::ViewMode mode) const; - void LogHistoryItemLoad(CalculatorApp::Common::ViewMode mode, int historyListSize, int loadedIndex) const; - void LogMemoryItemLoad(CalculatorApp::Common::ViewMode mode, int memoryListSize, int loadedIndex) const; + static TraceLogger ^ GetInstance(); + bool GetTraceLoggingProviderEnabled(); + void LogModeChange(CalculatorApp::Common::ViewMode mode); + void LogHistoryItemLoad(CalculatorApp::Common::ViewMode mode, int historyListSize, int loadedIndex); + void LogMemoryItemLoad(CalculatorApp::Common::ViewMode mode, int memoryListSize, int loadedIndex); void UpdateButtonUsage(CalculatorApp::NumbersAndOperatorsEnum button, CalculatorApp::Common::ViewMode mode); void LogButtonUsage(); void LogDateCalculationModeUsed(bool AddSubtractMode); - void UpdateWindowCount(size_t windowCount = 0); + void UpdateWindowCount(uint64 windowCount); + void DecreaseWindowCount(); bool IsWindowIdInLog(int windowId); - void LogVisualStateChanged(CalculatorApp::Common::ViewMode mode, std::wstring_view state, bool isAlwaysOnTop = false) const; + void LogVisualStateChanged(CalculatorApp::Common::ViewMode mode, Platform::String ^ state, bool isAlwaysOnTop); void LogWindowCreated(CalculatorApp::Common::ViewMode mode, int windowId); - void LogConverterInputReceived(CalculatorApp::Common::ViewMode mode) const; - void LogNavBarOpened() const; - - void LogError(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, std::wstring_view errorString); - void LogStandardException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ const std::exception& e) const; - void LogWinRTException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ winrt::hresult_error const& e) const; - void LogPlatformException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ Platform::Exception ^ e) const; - void LogInputPasted(CalculatorApp::Common::ViewMode mode) const; + void LogConverterInputReceived(CalculatorApp::Common::ViewMode mode); + void LogNavBarOpened(); + void LogError(CalculatorApp::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString); + internal : + void LogStandardException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ const std::exception& e); + void LogWinRTException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ winrt::hresult_error const& e); + void LogPlatformException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ Platform::Exception ^ e); + void LogInputPasted(CalculatorApp::Common::ViewMode mode); private: // Create an instance of TraceLogger @@ -64,11 +62,11 @@ namespace CalculatorApp // sampling is involved in Microsoft's diagnostic data collection process. // These keywords provide additional input into how frequently an event might be sampled. // The lower the level of the keyword, the higher the possibility that the corresponding event may be sampled. - void LogLevel1Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - void LogLevel2Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; - void LogLevel3Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; + void LogLevel1Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); + void LogLevel2Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); + void LogLevel3Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); - std::unique_ptr CreateTraceActivity(std::wstring_view activityName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields) const; + std::unique_ptr CreateTraceActivity(std::wstring_view activityName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); winrt::Windows::Foundation::Diagnostics::LoggingChannel g_calculatorProvider; @@ -76,7 +74,7 @@ namespace CalculatorApp std::vector windowIdLog; GUID sessionGuid; - size_t currentWindowCount = 0; + uint64 currentWindowCount = 0; winrt::Windows::Foundation::Diagnostics::LoggingActivity m_appLaunchActivity; }; diff --git a/src/CalcViewModel/Common/Utils.cpp b/src/CalcViewModel/Common/Utils.cpp index 89dd1e9f..368aa472 100644 --- a/src/CalcViewModel/Common/Utils.cpp +++ b/src/CalcViewModel/Common/Utils.cpp @@ -10,7 +10,6 @@ #include "Common/AppResourceProvider.h" #include "Common/ExpressionCommandSerializer.h" #include "Common/ExpressionCommandDeserializer.h" -#include "ViewState.h" using namespace CalculatorApp; using namespace CalculatorApp::Common; @@ -48,8 +47,8 @@ String ^ Utils::GetStringValue(String ^ input) double Utils::GetDoubleFromWstring(wstring input) { - wchar_t unWantedChars[] = { L' ', L',', 8234, 8235, 8236, 8237 }; - wstring ws = RemoveUnwantedCharsFromWstring(input, unWantedChars, 6); + constexpr wchar_t unWantedChars[] = { L' ', L',', 8234, 8235, 8236, 8237 }; + wstring ws = RemoveUnwantedCharsFromString(input, unWantedChars); return stod(ws); } @@ -81,47 +80,26 @@ bool Utils::IsLastCharacterTarget(_In_ wstring const& input, _In_ wchar_t target return !input.empty() && input.back() == target; } -// Return wstring after removing characters specified by unwantedChars array -wstring Utils::RemoveUnwantedCharsFromWstring(wstring input, wchar_t* unwantedChars, unsigned int size) -{ - for (unsigned int i = 0; i < size; ++i) - { - input.erase(std::remove(input.begin(), input.end(), unwantedChars[i]), input.end()); - } - return input; -} - void Utils::SerializeCommandsAndTokens( - _In_ shared_ptr>> const& tokens, - _In_ shared_ptr>> const& commands, + _In_ shared_ptr>> const& tokens, + _In_ shared_ptr>> const& commands, DataWriter ^ writer) { - unsigned int commandsSize; - IFTPlatformException(commands->GetSize(&commandsSize)); - // Save the size of the commands vector - writer->WriteUInt32(commandsSize); + writer->WriteUInt32(static_cast(commands->size())); SerializeCommandVisitor cmdVisitor(writer); - for (unsigned int i = 0; i < commandsSize; ++i) + for (const auto& exprCmd : *commands) { - shared_ptr exprCmd; - IFTPlatformException(commands->GetAt(i, &exprCmd)); - CalculationManager::CommandType commandType = exprCmd->GetCommandType(); writer->WriteInt32(static_cast(commandType)); exprCmd->Accept(cmdVisitor); } - unsigned int tokensSize; - IFTPlatformException(tokens->GetSize(&tokensSize)); - writer->WriteUInt32(tokensSize); + writer->WriteUInt32(static_cast(tokens->size())); - for (unsigned int i = 0; i < tokensSize; ++i) + for (const auto& eachToken : *tokens) { - pair eachToken; - IFTPlatformException(tokens->GetAt(i, &eachToken)); - auto stringData = ref new Platform::String(eachToken.first.c_str()); auto intData = eachToken.second; writer->WriteUInt32(writer->MeasureString(stringData)); @@ -130,9 +108,9 @@ void Utils::SerializeCommandsAndTokens( } } -const shared_ptr>> Utils::DeserializeCommands(DataReader ^ reader) +const shared_ptr>> Utils::DeserializeCommands(DataReader ^ reader) { - shared_ptr>> commandVector = make_shared>>(); + auto commandVector = make_shared>>(); auto commandVectorSize = reader->ReadUInt32(); CommandDeserializer cmdDeserializer(reader); @@ -141,26 +119,23 @@ const shared_ptr>> Utils::Deseri auto commandTypeInt = reader->ReadInt32(); CalculationManager::CommandType commandType = static_cast(commandTypeInt); shared_ptr exprCmd = cmdDeserializer.Deserialize(commandType); - commandVector->Append(exprCmd); + commandVector->push_back(exprCmd); } return commandVector; } -const shared_ptr>> Utils::DeserializeTokens(DataReader ^ reader) +const shared_ptr>> Utils::DeserializeTokens(DataReader ^ reader) { - shared_ptr>> tokenVector = make_shared>>(); + auto tokenVector = make_shared>>(); auto tokensSize = reader->ReadUInt32(); for (unsigned int i = 0; i < tokensSize; ++i) { - pair eachToken; auto stringDataLen = reader->ReadUInt32(); auto stringData = reader->ReadString(stringDataLen); auto intData = reader->ReadInt32(); - eachToken.first = stringData->Data(); - eachToken.second = intData; - tokenVector->Append(eachToken); + tokenVector->emplace_back(stringData->Data(), intData); } return tokenVector; diff --git a/src/CalcViewModel/Common/Utils.h b/src/CalcViewModel/Common/Utils.h index 45eeefe2..2c752382 100644 --- a/src/CalcViewModel/Common/Utils.h +++ b/src/CalcViewModel/Common/Utils.h @@ -3,7 +3,6 @@ #pragma once -#include "CalcManager/CalculatorVector.h" #include "CalcManager/ExpressionCommandInterface.h" #include "DelegateCommand.h" @@ -189,7 +188,7 @@ public: private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##n##Property; \ \ -public: +private: // Utilities for DependencyProperties namespace Utils @@ -380,17 +379,28 @@ namespace Utils void IFTPlatformException(HRESULT hr); Platform::String ^ GetStringValue(Platform::String ^ input); bool IsLastCharacterTarget(std::wstring const& input, wchar_t target); - std::wstring RemoveUnwantedCharsFromWstring(std::wstring inputString, wchar_t* unwantedChars, unsigned int size); + + // Return wstring after removing characters specified by unwantedChars array + template + std::wstring RemoveUnwantedCharsFromString(std::wstring inputString, const wchar_t (&unwantedChars)[N]) + { + for (const wchar_t unwantedChar : unwantedChars) + { + inputString.erase(std::remove(inputString.begin(), inputString.end(), unwantedChar), inputString.end()); + } + return inputString; + } + double GetDoubleFromWstring(std::wstring input); int GetWindowId(); void RunOnUIThreadNonblocking(std::function&& function, _In_ Windows::UI::Core::CoreDispatcher ^ currentDispatcher); void SerializeCommandsAndTokens( - _In_ std::shared_ptr>> const& tokens, - _In_ std::shared_ptr>> const& commands, + _In_ std::shared_ptr>> const& tokens, + _In_ std::shared_ptr>> const& commands, Windows::Storage::Streams::DataWriter ^ writer); - const std::shared_ptr>> DeserializeCommands(Windows::Storage::Streams::DataReader ^ reader); - const std::shared_ptr>> DeserializeTokens(Windows::Storage::Streams::DataReader ^ reader); + const std::shared_ptr>> DeserializeCommands(Windows::Storage::Streams::DataReader ^ reader); + const std::shared_ptr>> DeserializeTokens(Windows::Storage::Streams::DataReader ^ reader); Windows::Foundation::DateTime GetUniversalSystemTime(); bool IsDateTimeOlderThan(Windows::Foundation::DateTime dateTime, const long long duration); diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp index 5180de47..d098885e 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -132,8 +132,8 @@ CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr clie m_ratioFormatter->IsDecimalPointAlwaysDisplayed = true; m_ratioFormatter->FractionDigits = FORMATTER_RATE_FRACTION_PADDING; - m_ratioFormat = AppResourceProvider::GetInstance().GetResourceString(L"CurrencyFromToRatioFormat")->Data(); - m_timestampFormat = AppResourceProvider::GetInstance().GetResourceString(L"CurrencyTimestampFormat")->Data(); + m_ratioFormat = AppResourceProvider::GetInstance()->GetResourceString(L"CurrencyFromToRatioFormat"); + m_timestampFormat = AppResourceProvider::GetInstance()->GetResourceString(L"CurrencyTimestampFormat"); } CurrencyDataLoader::~CurrencyDataLoader() @@ -300,16 +300,18 @@ pair CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const U double ratio = (iter2->second).ratio; double rounded = RoundCurrencyRatio(ratio); - wstring digitSymbol = wstring{ LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'1') }; - wstring roundedFormat = m_ratioFormatter->Format(rounded)->Data(); + auto digit = LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'1'); + auto digitSymbol = ref new String(&digit, 1); + auto roundedFormat = m_ratioFormatter->Format(rounded); - wstring ratioString = LocalizationStringUtil::GetLocalizedString( - m_ratioFormat.c_str(), digitSymbol.c_str(), unit1.abbreviation.c_str(), roundedFormat.c_str(), unit2.abbreviation.c_str()); + auto ratioString = LocalizationStringUtil::GetLocalizedString( + m_ratioFormat, digitSymbol, StringReference(unit1.abbreviation.c_str()), roundedFormat, StringReference(unit2.abbreviation.c_str())); - wstring accessibleRatioString = LocalizationStringUtil::GetLocalizedString( - m_ratioFormat.c_str(), digitSymbol.c_str(), unit1.accessibleName.c_str(), roundedFormat.c_str(), unit2.accessibleName.c_str()); + auto accessibleRatioString = + LocalizationStringUtil::GetLocalizedString( + m_ratioFormat, digitSymbol, StringReference(unit1.accessibleName.c_str()), roundedFormat, StringReference(unit2.accessibleName.c_str())); - return make_pair(ratioString, accessibleRatioString); + return make_pair(ratioString->Data(), accessibleRatioString->Data()); } } } @@ -349,12 +351,12 @@ future CurrencyDataLoader::TryLoadDataFromCacheAsync() } catch (Exception ^ ex) { - TraceLogger::GetInstance().LogPlatformException(ViewMode::Currency, __FUNCTIONW__, ex); + TraceLogger::GetInstance()->LogPlatformException(ViewMode::Currency, __FUNCTIONW__, ex); co_return false; } catch (const exception& e) { - TraceLogger::GetInstance().LogStandardException(ViewMode::Currency, __FUNCTIONW__, e); + TraceLogger::GetInstance()->LogStandardException(ViewMode::Currency, __FUNCTIONW__, e); co_return false; } catch (...) @@ -459,12 +461,12 @@ future CurrencyDataLoader::TryLoadDataFromWebAsync() } catch (Exception ^ ex) { - TraceLogger::GetInstance().LogPlatformException(ViewMode::Currency, __FUNCTIONW__, ex); + TraceLogger::GetInstance()->LogPlatformException(ViewMode::Currency, __FUNCTIONW__, ex); co_return false; } catch (const exception& e) { - TraceLogger::GetInstance().LogStandardException(ViewMode::Currency, __FUNCTIONW__, e); + TraceLogger::GetInstance()->LogStandardException(ViewMode::Currency, __FUNCTIONW__, e); co_return false; } catch (...) @@ -480,7 +482,7 @@ future CurrencyDataLoader::TryLoadDataFromWebOverrideAsync() if (!didLoad) { m_loadStatus = CurrencyLoadStatus::FailedToLoad; - TraceLogger::GetInstance().LogError(ViewMode::Currency, L"CurrencyDataLoader::TryLoadDataFromWebOverrideAsync", L"UserRequestedRefreshFailed"); + TraceLogger::GetInstance()->LogError(ViewMode::Currency, L"CurrencyDataLoader::TryLoadDataFromWebOverrideAsync", L"UserRequestedRefreshFailed"); } co_return didLoad; @@ -747,21 +749,19 @@ void CurrencyDataLoader::UpdateDisplayedTimestamp() } wstring CurrencyDataLoader::GetCurrencyTimestamp() { - wstring timestamp = L""; - DateTime epoch{}; if (m_cacheTimestamp.UniversalTime != epoch.UniversalTime) { - DateTimeFormatter ^ dateFormatter = ref new DateTimeFormatter(L"{month.abbreviated} {day.integer}, {year.full}"); - wstring date = dateFormatter->Format(m_cacheTimestamp)->Data(); + DateTimeFormatter ^ dateFormatter = ref new DateTimeFormatter(L"shortdate"); + auto date = dateFormatter->Format(m_cacheTimestamp); DateTimeFormatter ^ timeFormatter = ref new DateTimeFormatter(L"shorttime"); - wstring time = timeFormatter->Format(m_cacheTimestamp)->Data(); + auto time = timeFormatter->Format(m_cacheTimestamp); - timestamp = LocalizationStringUtil::GetLocalizedString(m_timestampFormat.c_str(), date.c_str(), time.c_str()); + return LocalizationStringUtil::GetLocalizedString(m_timestampFormat, date, time)->Data(); } - return timestamp; + return L""; } #pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321 diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h index 7a28c6c7..d2548dcf 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once @@ -124,9 +124,9 @@ namespace CalculatorApp std::shared_ptr m_vmCallback; Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_ratioFormatter; - std::wstring m_ratioFormat; + Platform::String ^ m_ratioFormat; Windows::Foundation::DateTime m_cacheTimestamp; - std::wstring m_timestampFormat; + Platform::String ^ m_timestampFormat; CurrencyLoadStatus m_loadStatus; diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp index e69b8e2c..f90260d4 100644 --- a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp +++ b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp @@ -953,7 +953,7 @@ void UnitConverterDataLoader::GetConversionData(_In_ unordered_mapData(); + return AppResourceProvider::GetInstance()->GetResourceString(stringId)->Data(); } void UnitConverterDataLoader::GetExplicitConversionData(_In_ unordered_map>& unitToUnitConversionList) diff --git a/src/CalcViewModel/DateCalculatorViewModel.cpp b/src/CalcViewModel/DateCalculatorViewModel.cpp index e89c136a..20ee012b 100644 --- a/src/CalcViewModel/DateCalculatorViewModel.cpp +++ b/src/CalcViewModel/DateCalculatorViewModel.cpp @@ -45,13 +45,13 @@ DateCalculatorViewModel::DateCalculatorViewModel() , m_StrDateResult(L"") , m_StrDateResultAutomationName(L"") { - const auto& localizationSettings = LocalizationSettings::GetInstance(); + const auto & localizationSettings = LocalizationSettings::GetInstance(); // Initialize Date Output format instances InitializeDateOutputFormats(localizationSettings.GetCalendarIdentifier()); // Initialize Date Calc engine - m_dateCalcEngine = make_shared(localizationSettings.GetCalendarIdentifier()); + m_dateCalcEngine = ref new DateCalculationEngine(localizationSettings.GetCalendarIdentifier()); // Initialize dates of DatePicker controls to today's date auto calendar = ref new Calendar(); // We force the timezone to UTC, in order to avoid being affected by Daylight Saving Time @@ -111,20 +111,20 @@ void DateCalculatorViewModel::OnPropertyChanged(_In_ String ^ prop) void DateCalculatorViewModel::OnInputsChanged() { - DateDifference dateDiff; - if (m_IsDateDiffMode) { DateTime clippedFromDate = ClipTime(FromDate, true); DateTime clippedToDate = ClipTime(ToDate, true); // Calculate difference between two dates - if (m_dateCalcEngine->TryGetDateDifference(clippedFromDate, clippedToDate, m_daysOutputFormat, &dateDiff)) + auto dateDiff = m_dateCalcEngine->TryGetDateDifference(clippedFromDate, clippedToDate, m_daysOutputFormat); + if (dateDiff != nullptr) { - DateDiffResultInDays = dateDiff; - if (m_dateCalcEngine->TryGetDateDifference(clippedFromDate, clippedToDate, m_allDateUnitsOutputFormat, &dateDiff)) + DateDiffResultInDays = dateDiff->Value; + dateDiff = m_dateCalcEngine->TryGetDateDifference(clippedFromDate, clippedToDate, m_allDateUnitsOutputFormat); + if (dateDiff != nullptr) { - DateDiffResult = dateDiff; + DateDiffResult = dateDiff->Value; } else { @@ -140,26 +140,28 @@ void DateCalculatorViewModel::OnInputsChanged() } else { + DateDifference dateDiff; dateDiff.day = DaysOffset; dateDiff.month = MonthsOffset; dateDiff.year = YearsOffset; - DateTime dateTimeResult; + IBox ^ dateTimeResult; if (m_IsAddMode) { // Add number of Days, Months and Years to a Date - IsOutOfBound = !m_dateCalcEngine->AddDuration(StartDate, dateDiff, &dateTimeResult); + dateTimeResult = m_dateCalcEngine->AddDuration(StartDate, dateDiff); } else { // Subtract number of Days, Months and Years from a Date - IsOutOfBound = !m_dateCalcEngine->SubtractDuration(StartDate, dateDiff, &dateTimeResult); + dateTimeResult = m_dateCalcEngine->SubtractDuration(StartDate, dateDiff); } + IsOutOfBound = dateTimeResult == nullptr; if (!m_isOutOfBound) { - DateResult = dateTimeResult; + DateResult = dateTimeResult->Value; } } } @@ -172,17 +174,16 @@ void DateCalculatorViewModel::UpdateDisplayResult() { IsDiffInDays = false; StrDateDiffResultInDays = L""; - StrDateDiffResult = AppResourceProvider::GetInstance().GetResourceString(L"CalculationFailed"); + StrDateDiffResult = AppResourceProvider::GetInstance()->GetResourceString(L"CalculationFailed"); } else if (m_dateDiffResultInDays.day == 0) { // to and from dates the same IsDiffInDays = true; StrDateDiffResultInDays = L""; - StrDateDiffResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_SameDates"); + StrDateDiffResult = AppResourceProvider::GetInstance()->GetResourceString(L"Date_SameDates"); } - else if (m_dateDiffResult == DateDifferenceUnknown || - (m_dateDiffResult.year == 0 && m_dateDiffResult.month == 0 && m_dateDiffResult.week == 0)) + else if (m_dateDiffResult == DateDifferenceUnknown || (m_dateDiffResult.year == 0 && m_dateDiffResult.month == 0 && m_dateDiffResult.week == 0)) { IsDiffInDays = true; StrDateDiffResultInDays = L""; @@ -206,7 +207,7 @@ void DateCalculatorViewModel::UpdateDisplayResult() if (m_isOutOfBound) { // Display Date out of bound message - StrDateResult = AppResourceProvider::GetInstance().GetResourceString(L"Date_OutOfBoundMessage"); + StrDateResult = AppResourceProvider::GetInstance()->GetResourceString(L"Date_OutOfBoundMessage"); } else { @@ -218,16 +219,14 @@ void DateCalculatorViewModel::UpdateDisplayResult() void DateCalculatorViewModel::UpdateStrDateDiffResultAutomationName() { - String ^ automationFormat = AppResourceProvider::GetInstance().GetResourceString(L"Date_DifferenceResultAutomationName"); - wstring localizedAutomationName = LocalizationStringUtil::GetLocalizedString(automationFormat->Data(), StrDateDiffResult->Data()); - StrDateDiffResultAutomationName = ref new String(localizedAutomationName.c_str()); + String ^ automationFormat = AppResourceProvider::GetInstance()->GetResourceString(L"Date_DifferenceResultAutomationName"); + StrDateDiffResultAutomationName = LocalizationStringUtil::GetLocalizedString(automationFormat, StrDateDiffResult); } void DateCalculatorViewModel::UpdateStrDateResultAutomationName() { - String ^ automationFormat = AppResourceProvider::GetInstance().GetResourceString(L"Date_ResultingDateAutomationName"); - wstring localizedAutomationName = LocalizationStringUtil::GetLocalizedString(automationFormat->Data(), StrDateResult->Data()); - StrDateResultAutomationName = ref new String(localizedAutomationName.c_str()); + String ^ automationFormat = AppResourceProvider::GetInstance()->GetResourceString(L"Date_ResultingDateAutomationName"); + StrDateResultAutomationName = LocalizationStringUtil::GetLocalizedString(automationFormat, StrDateResult); } void DateCalculatorViewModel::InitializeDateOutputFormats(_In_ String ^ calendarIdentifier) @@ -247,21 +246,21 @@ String ^ DateCalculatorViewModel::GetDateDiffString() const { wstring result; bool addDelimiter = false; - AppResourceProvider resourceLoader = AppResourceProvider::GetInstance(); + AppResourceProvider ^ resourceLoader = AppResourceProvider::GetInstance(); auto yearCount = m_dateDiffResult.year; if (yearCount > 0) { result += GetLocalizedNumberString(yearCount)->Data(); - result += L" "; + result += L' '; if (yearCount > 1) { - result += resourceLoader.GetResourceString(L"Date_Years")->Data(); + result += resourceLoader->GetResourceString(L"Date_Years")->Data(); } else { - result += resourceLoader.GetResourceString(L"Date_Year")->Data(); + result += resourceLoader->GetResourceString(L"Date_Year")->Data(); } // set the flags to add a delimiter whenever the next unit is added @@ -281,15 +280,15 @@ String ^ DateCalculatorViewModel::GetDateDiffString() const } result += GetLocalizedNumberString(monthCount)->Data(); - result += L" "; + result += L' '; if (monthCount > 1) { - result += resourceLoader.GetResourceString(L"Date_Months")->Data(); + result += resourceLoader->GetResourceString(L"Date_Months")->Data(); } else { - result += resourceLoader.GetResourceString(L"Date_Month")->Data(); + result += resourceLoader->GetResourceString(L"Date_Month")->Data(); } } @@ -306,15 +305,15 @@ String ^ DateCalculatorViewModel::GetDateDiffString() const } result += GetLocalizedNumberString(weekCount)->Data(); - result += L" "; + result += L' '; if (weekCount > 1) { - result += resourceLoader.GetResourceString(L"Date_Weeks")->Data(); + result += resourceLoader->GetResourceString(L"Date_Weeks")->Data(); } else { - result += resourceLoader.GetResourceString(L"Date_Week")->Data(); + result += resourceLoader->GetResourceString(L"Date_Week")->Data(); } } @@ -331,15 +330,15 @@ String ^ DateCalculatorViewModel::GetDateDiffString() const } result += GetLocalizedNumberString(dayCount)->Data(); - result += L" "; + result += L' '; if (dayCount > 1) { - result += resourceLoader.GetResourceString(L"Date_Days")->Data(); + result += resourceLoader->GetResourceString(L"Date_Days")->Data(); } else { - result += resourceLoader.GetResourceString(L"Date_Day")->Data(); + result += resourceLoader->GetResourceString(L"Date_Day")->Data(); } } @@ -349,16 +348,16 @@ String ^ DateCalculatorViewModel::GetDateDiffString() const String ^ DateCalculatorViewModel::GetDateDiffStringInDays() const { wstring result = GetLocalizedNumberString(m_dateDiffResultInDays.day)->Data(); - result += L" "; + result += L' '; // Display the result as '1 day' or 'N days' if (m_dateDiffResultInDays.day > 1) { - result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Days")->Data(); + result += AppResourceProvider::GetInstance()->GetResourceString(L"Date_Days")->Data(); } else { - result += AppResourceProvider::GetInstance().GetResourceString(L"Date_Day")->Data(); + result += AppResourceProvider::GetInstance()->GetResourceString(L"Date_Day")->Data(); } return ref new String(result.data()); diff --git a/src/CalcViewModel/DateCalculatorViewModel.h b/src/CalcViewModel/DateCalculatorViewModel.h index c1cce242..d9e73f4b 100644 --- a/src/CalcViewModel/DateCalculatorViewModel.h +++ b/src/CalcViewModel/DateCalculatorViewModel.h @@ -176,7 +176,7 @@ namespace CalculatorApp CalculatorApp::Common::DateCalculation::DateDifference m_dateDiffResultInDays; // Private members - std::shared_ptr m_dateCalcEngine; + CalculatorApp::Common::DateCalculation::DateCalculationEngine ^ m_dateCalcEngine; CalculatorApp::Common::DateCalculation::DateUnit m_daysOutputFormat; CalculatorApp::Common::DateCalculation::DateUnit m_allDateUnitsOutputFormat; Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ m_dateTimeFormatter; diff --git a/src/CalcViewModel/HistoryItemViewModel.cpp b/src/CalcViewModel/HistoryItemViewModel.cpp index 63d5e966..95775bb9 100644 --- a/src/CalcViewModel/HistoryItemViewModel.cpp +++ b/src/CalcViewModel/HistoryItemViewModel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -13,8 +13,8 @@ using namespace Platform; HistoryItemViewModel::HistoryItemViewModel( String ^ expression, String ^ result, - _In_ const shared_ptr>>& spTokens, - _In_ const shared_ptr>>& spCommands) + _In_ const shared_ptr>>& spTokens, + _In_ const shared_ptr>>& spCommands) : m_expression(expression) , m_result(result) , m_spTokens(spTokens) @@ -27,47 +27,16 @@ HistoryItemViewModel::HistoryItemViewModel( String ^ HistoryItemViewModel::GetAccessibleExpressionFromTokens( - _In_ shared_ptr>> const& spTokens, + _In_ shared_ptr>> const& spTokens, _In_ String ^ fallbackExpression) { // updating accessibility names for expression and result - wstringstream accExpression{}; - accExpression << L""; + wstring accExpression{}; - unsigned int nTokens; - HRESULT hr = spTokens->GetSize(&nTokens); - if (SUCCEEDED(hr)) + for (const auto& tokenItem : *spTokens) { - pair tokenItem; - for (unsigned int i = 0; i < nTokens; i++) - { - hr = spTokens->GetAt(i, &tokenItem); - if (FAILED(hr)) - { - break; - } - - wstring token = tokenItem.first; - accExpression << LocalizationService::GetNarratorReadableToken(StringReference(token.c_str()))->Data(); - } + accExpression += LocalizationService::GetNarratorReadableToken(StringReference(tokenItem.first.c_str()))->Data(); } - if (SUCCEEDED(hr)) - { - wstring expressionSuffix{}; - hr = spTokens->GetExpressionSuffix(&expressionSuffix); - if (SUCCEEDED(hr)) - { - accExpression << expressionSuffix; - } - } - - if (FAILED(hr)) - { - return LocalizationService::GetNarratorReadableString(fallbackExpression); - } - else - { - return ref new String(accExpression.str().c_str()); - } + return ref new String(accExpression.c_str()); } diff --git a/src/CalcViewModel/HistoryItemViewModel.h b/src/CalcViewModel/HistoryItemViewModel.h index fae51e69..cc479518 100644 --- a/src/CalcViewModel/HistoryItemViewModel.h +++ b/src/CalcViewModel/HistoryItemViewModel.h @@ -3,7 +3,6 @@ #pragma once -#include "CalcManager/CalculatorVector.h" #include "CalcManager/ExpressionCommandInterface.h" namespace CalculatorApp @@ -17,15 +16,15 @@ namespace CalculatorApp HistoryItemViewModel( Platform::String ^ expression, Platform::String ^ result, - _In_ std::shared_ptr>> const& spTokens, - _In_ std::shared_ptr>> const& spCommands); + _In_ std::shared_ptr>> const& spTokens, + _In_ std::shared_ptr>> const& spCommands); - std::shared_ptr>> const& GetTokens() + std::shared_ptr>> const& GetTokens() { return m_spTokens; } - std::shared_ptr>> const& GetCommands() + std::shared_ptr>> const& GetCommands() { return m_spCommands; } @@ -62,7 +61,7 @@ namespace CalculatorApp private : static Platform::String ^ GetAccessibleExpressionFromTokens( - _In_ std::shared_ptr>> const& spTokens, + _In_ std::shared_ptr>> const& spTokens, _In_ Platform::String ^ fallbackExpression); private: @@ -70,8 +69,8 @@ namespace CalculatorApp Platform::String ^ m_accExpression; Platform::String ^ m_accResult; Platform::String ^ m_result; - std::shared_ptr>> m_spTokens; - std::shared_ptr>> m_spCommands; + std::shared_ptr>> m_spTokens; + std::shared_ptr>> m_spCommands; }; } } diff --git a/src/CalcViewModel/HistoryViewModel.cpp b/src/CalcViewModel/HistoryViewModel.cpp index 8da5007a..58bd726d 100644 --- a/src/CalcViewModel/HistoryViewModel.cpp +++ b/src/CalcViewModel/HistoryViewModel.cpp @@ -120,7 +120,7 @@ void HistoryViewModel::ShowItem(_In_ HistoryItemViewModel ^ e) { unsigned int index; Items->IndexOf(e, &index); - TraceLogger::GetInstance().LogHistoryItemLoad((ViewMode)m_currentMode, ItemSize, (int)(index)); + TraceLogger::GetInstance()->LogHistoryItemLoad((ViewMode)m_currentMode, ItemSize, (int)(index)); HistoryItemClicked(e); } @@ -164,7 +164,11 @@ void HistoryViewModel::OnClearCommand(_In_ Platform::Object ^ e) UpdateItemSize(); } - MakeHistoryClearedNarratorAnnouncement(HistoryResourceKeys::HistoryCleared, m_localizedHistoryCleared); + if (m_localizedHistoryCleared == nullptr) + { + m_localizedHistoryCleared = AppResourceProvider::GetInstance()->GetResourceString(HistoryResourceKeys::HistoryCleared); + } + HistoryAnnouncement = CalculatorAnnouncement::GetHistoryClearedAnnouncement(m_localizedHistoryCleared); } } @@ -263,16 +267,16 @@ void HistoryViewModel::ClearHistory() void HistoryViewModel::SaveHistory() { ApplicationDataContainer ^ historyContainer = GetHistoryContainer(m_currentMode); - auto currentHistoryVector = m_calculatorManager->GetHistoryItems(m_currentMode); + auto const& currentHistoryVector = m_calculatorManager->GetHistoryItems(m_currentMode); bool failure = false; int index = 0; Platform::String ^ serializedHistoryItem; - for (auto iter = currentHistoryVector.begin(); iter != currentHistoryVector.end(); ++iter) + for (auto const& item : currentHistoryVector) { try { - serializedHistoryItem = SerializeHistoryItem(*iter); + serializedHistoryItem = SerializeHistoryItem(item); historyContainer->Values->Insert(index.ToString(), serializedHistoryItem); } catch (Platform::Exception ^) @@ -370,10 +374,3 @@ void HistoryViewModel::UpdateItemSize() { ItemSize = Items->Size; } - -void HistoryViewModel::MakeHistoryClearedNarratorAnnouncement(String ^ resourceKey, String ^ &formatVariable) -{ - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(resourceKey, formatVariable); - - HistoryAnnouncement = CalculatorAnnouncement::GetHistoryClearedAnnouncement(announcement); -} diff --git a/src/CalcViewModel/HistoryViewModel.h b/src/CalcViewModel/HistoryViewModel.h index 4ed61d92..75321d39 100644 --- a/src/CalcViewModel/HistoryViewModel.h +++ b/src/CalcViewModel/HistoryViewModel.h @@ -68,8 +68,6 @@ namespace CalculatorApp void UpdateHistoryVectorLength(_In_ int newValue, _In_ CalculationManager::CALCULATOR_MODE cMode); bool IsValid(_In_ CalculationManager::HISTORYITEM item); - void MakeHistoryClearedNarratorAnnouncement(Platform::String ^ resourceKey, Platform::String ^ &formatVariable); - friend class CalculatorDisplay; void UpdateItemSize(); }; diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp index c9717b8b..3b3647dd 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp @@ -14,6 +14,7 @@ using namespace CalculatorApp::Common; using namespace CalculatorApp::Common::Automation; using namespace CalculatorApp::ViewModel; using namespace CalculationManager; +using namespace concurrency; using namespace Platform; using namespace Platform::Collections; using namespace std; @@ -25,6 +26,7 @@ using namespace Windows::UI::Popups; using namespace Windows::Storage::Streams; using namespace Windows::Foundation::Collections; using namespace Utils; +using namespace concurrency; constexpr int StandardModePrecision = 16; constexpr int ScientificModePrecision = 32; @@ -67,20 +69,17 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() , m_HexDisplayValue(L"0") , m_BinaryDisplayValue(L"0") , m_OctalDisplayValue(L"0") + , m_BinaryDigits(ref new Vector(64, false)) , m_standardCalculatorManager(&m_calculatorDisplay, &m_resourceProvider) , m_ExpressionTokens(ref new Vector()) , m_MemorizedNumbers(ref new Vector()) , m_IsMemoryEmpty(true) , m_IsFToEChecked(false) - , m_isShiftChecked(false) , m_IsShiftProgrammerChecked(false) - , m_IsQwordEnabled(true) - , m_IsDwordEnabled(true) - , m_IsWordEnabled(true) - , m_IsByteEnabled(true) + , m_valueBitLength(BitLength::BitLengthQWord) , m_isBitFlipChecked(false) - , m_isBinaryBitFlippingEnabled(false) - , m_CurrentRadixType(RADIX_TYPE::DEC_RADIX) + , m_IsBinaryBitFlippingEnabled(false) + , m_CurrentRadixType(NumberBase::DecBase) , m_CurrentAngleType(NumbersAndOperatorsEnum::Degree) , m_Announcement(nullptr) , m_OpenParenthesisCount(0) @@ -94,17 +93,20 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() , m_localizedMemoryCleared(nullptr) , m_localizedOpenParenthesisCountChangedAutomationFormat(nullptr) , m_localizedNoRightParenthesisAddedFormat(nullptr) + , m_TokenPosition(-1) + , m_isLastOperationHistoryLoad(false) { WeakReference calculatorViewModel(this); + auto appResourceProvider = AppResourceProvider::GetInstance(); m_calculatorDisplay.SetCallback(calculatorViewModel); - m_expressionAutomationNameFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::CalculatorExpression); - m_localizedCalculationResultAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::CalculatorResults); + m_expressionAutomationNameFormat = appResourceProvider->GetResourceString(CalculatorResourceKeys::CalculatorExpression); + m_localizedCalculationResultAutomationFormat = appResourceProvider->GetResourceString(CalculatorResourceKeys::CalculatorResults); m_localizedCalculationResultDecimalAutomationFormat = - AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::CalculatorResults_DecimalSeparator_Announced); - m_localizedHexaDecimalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::HexButton); - m_localizedDecimalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::DecButton); - m_localizedOctalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::OctButton); - m_localizedBinaryAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::BinButton); + appResourceProvider->GetResourceString(CalculatorResourceKeys::CalculatorResults_DecimalSeparator_Announced); + m_localizedHexaDecimalAutomationFormat = appResourceProvider->GetResourceString(CalculatorResourceKeys::HexButton); + m_localizedDecimalAutomationFormat = appResourceProvider->GetResourceString(CalculatorResourceKeys::DecButton); + m_localizedOctalAutomationFormat = appResourceProvider->GetResourceString(CalculatorResourceKeys::OctButton); + m_localizedBinaryAutomationFormat = appResourceProvider->GetResourceString(CalculatorResourceKeys::BinButton); // Initialize the Automation Name CalculationResultAutomationName = GetLocalizedStringFormat(m_localizedCalculationResultAutomationFormat, m_DisplayValue); @@ -130,9 +132,6 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() IsDecimalEnabled = true; AreHistoryShortcutsEnabled = true; AreProgrammerRadixOperatorsEnabled = false; - - m_tokenPosition = -1; - m_isLastOperationHistoryLoad = false; } String ^ StandardCalculatorViewModel::LocalizeDisplayValue(_In_ wstring const& displayValue, _In_ bool isError) @@ -168,7 +167,7 @@ String ^ StandardCalculatorViewModel::CalculateNarratorDisplayValue(_In_ wstring } // In Programmer modes using non-base10, we want the strings to be read as literal digits. - if (IsProgrammer && CurrentRadixType != RADIX_TYPE::DEC_RADIX) + if (IsProgrammer && CurrentRadixType != NumberBase::DecBase) { localizedValue = GetNarratorStringReadRawNumbers(localizedValue); } @@ -178,30 +177,29 @@ String ^ StandardCalculatorViewModel::CalculateNarratorDisplayValue(_In_ wstring String ^ StandardCalculatorViewModel::GetNarratorStringReadRawNumbers(_In_ String ^ localizedDisplayValue) { - wstringstream wss; - auto& locSettings = LocalizationSettings::GetInstance(); + wstring ws; + const auto& locSettings = LocalizationSettings::GetInstance(); // Insert a space after each digit in the string, to force Narrator to read them as separate numbers. - wstring wstrValue(localizedDisplayValue->Data()); - for (wchar_t& c : wstrValue) + for (const wchar_t& c : localizedDisplayValue) { - wss << c; + ws += c; if (locSettings.IsLocalizedHexDigit(c)) { - wss << L' '; + ws += L' '; } } - return ref new String(wss.str().c_str()); + return ref new String(ws.c_str()); } -void StandardCalculatorViewModel::SetPrimaryDisplay(_In_ wstring const& displayStringValue, _In_ bool isError) +void StandardCalculatorViewModel::SetPrimaryDisplay(_In_ String ^ displayStringValue, _In_ bool isError) { - String ^ localizedDisplayStringValue = LocalizeDisplayValue(displayStringValue, isError); + String ^ localizedDisplayStringValue = LocalizeDisplayValue(displayStringValue->Data(), isError); // Set this variable before the DisplayValue is modified, Otherwise the DisplayValue will // not match what the narrator is saying - m_CalculationResultAutomationName = CalculateNarratorDisplayValue(displayStringValue, localizedDisplayStringValue, isError); + m_CalculationResultAutomationName = CalculateNarratorDisplayValue(displayStringValue->Data(), localizedDisplayStringValue, isError); AreAlwaysOnTopResultsUpdated = false; if (DisplayValue != localizedDisplayStringValue) @@ -242,10 +240,13 @@ void StandardCalculatorViewModel::SetOpenParenthesisCountNarratorAnnouncement() wstring localizedParenthesisCount = to_wstring(m_OpenParenthesisCount).c_str(); LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount); - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::OpenParenthesisCountAutomationFormat, - m_localizedOpenParenthesisCountChangedAutomationFormat, - localizedParenthesisCount.c_str()); + if (m_localizedOpenParenthesisCountChangedAutomationFormat == nullptr) + { + m_localizedOpenParenthesisCountChangedAutomationFormat = + AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::OpenParenthesisCountAutomationFormat); + } + String ^ announcement = + LocalizationStringUtil::GetLocalizedString(m_localizedOpenParenthesisCountChangedAutomationFormat, StringReference(localizedParenthesisCount.c_str())); Announcement = CalculatorAnnouncement::GetOpenParenthesisCountChangedAnnouncement(announcement); } @@ -257,10 +258,13 @@ void StandardCalculatorViewModel::OnNoRightParenAdded() void StandardCalculatorViewModel::SetNoParenAddedNarratorAnnouncement() { - String ^ announcement = - LocalizationStringUtil::GetLocalizedNarratorAnnouncement(CalculatorResourceKeys::NoParenthesisAdded, m_localizedNoRightParenthesisAddedFormat); + if (m_localizedNoRightParenthesisAddedFormat == nullptr) + { + m_localizedNoRightParenthesisAddedFormat = + AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::NoParenthesisAdded); + } - Announcement = CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(announcement); + Announcement = CalculatorAnnouncement::GetNoRightParenthesisAddedAnnouncement(m_localizedNoRightParenthesisAddedFormat); } void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionCommandType) @@ -292,8 +296,8 @@ void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionC } void StandardCalculatorViewModel::SetExpressionDisplay( - _Inout_ shared_ptr>> const& tokens, - _Inout_ shared_ptr>> const& commands) + _Inout_ shared_ptr>> const& tokens, + _Inout_ shared_ptr>> const& commands) { m_tokens = tokens; m_commands = commands; @@ -308,11 +312,11 @@ void StandardCalculatorViewModel::SetExpressionDisplay( } void StandardCalculatorViewModel::SetHistoryExpressionDisplay( - _Inout_ shared_ptr>> const& tokens, - _Inout_ shared_ptr>> const& commands) + _Inout_ shared_ptr>> const& tokens, + _Inout_ shared_ptr>> const& commands) { - m_tokens = make_shared>>(*tokens); - m_commands = make_shared>>(*commands); + m_tokens = make_shared>>(*tokens); + m_commands = make_shared>>(*commands); IsEditingEnabled = false; // Setting the History Item Load Mode so that UI does not get updated with recalculation of every token @@ -322,12 +326,11 @@ void StandardCalculatorViewModel::SetHistoryExpressionDisplay( m_isLastOperationHistoryLoad = true; } -void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr>> const& tokens) +void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr>> const& tokens) { AreTokensUpdated = false; - unsigned int nTokens = 0; - tokens->GetSize(&nTokens); + const size_t nTokens = tokens->size(); if (nTokens == 0) { @@ -335,51 +338,48 @@ void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr currentToken; const auto& localizer = LocalizationSettings::GetInstance(); const wstring separator = L" "; for (unsigned int i = 0; i < nTokens; ++i) { - if (SUCCEEDED(tokens->GetAt(i, ¤tToken))) + auto currentToken = (*tokens)[i]; + + Common::TokenType type; + bool isEditable = currentToken.second != -1; + localizer.LocalizeDisplayValue(&(currentToken.first)); + + if (!isEditable) { - Common::TokenType type; - bool isEditable = (currentToken.second == -1) ? false : true; - localizer.LocalizeDisplayValue(&(currentToken.first)); + type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator; + } + else + { + const shared_ptr& command = m_commands->at(currentToken.second); + type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator; + } - if (!isEditable) + auto currentTokenString = StringReference(currentToken.first.c_str()); + if (i < m_ExpressionTokens->Size) + { + auto existingItem = m_ExpressionTokens->GetAt(i); + if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString)) { - type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator; - } - else - { - shared_ptr command; - IFTPlatformException(m_commands->GetAt(static_cast(currentToken.second), &command)); - type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator; - } - - auto currentTokenString = ref new String(currentToken.first.c_str()); - if (i < m_ExpressionTokens->Size) - { - auto existingItem = m_ExpressionTokens->GetAt(i); - if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString)) - { - existingItem->TokenPosition = i; - existingItem->IsTokenEditable = isEditable; - existingItem->CommandIndex = 0; - } - else - { - auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); - m_ExpressionTokens->InsertAt(i, expressionToken); - } + existingItem->TokenPosition = i; + existingItem->IsTokenEditable = isEditable; + existingItem->CommandIndex = 0; } else { auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); - m_ExpressionTokens->Append(expressionToken); + m_ExpressionTokens->InsertAt(i, expressionToken); } } + else + { + auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens->Append(expressionToken); + } } while (m_ExpressionTokens->Size != nTokens) @@ -453,7 +453,7 @@ void StandardCalculatorViewModel::FtoEButtonToggled() void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) { - DisplayExpressionToken ^ displayExpressionToken = ExpressionTokens->GetAt(m_tokenPosition); + DisplayExpressionToken ^ displayExpressionToken = ExpressionTokens->GetAt(m_TokenPosition); if (displayExpressionToken == nullptr) { return; @@ -581,7 +581,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) } String ^ updatedData = ref new String(temp); - UpdateOperand(m_tokenPosition, updatedData); + UpdateOperand(m_TokenPosition, updatedData); displayExpressionToken->Token = updatedData; IsOperandUpdatedUsingViewModel = true; displayExpressionToken->CommandIndex = commandIndex; @@ -610,7 +610,7 @@ void StandardCalculatorViewModel::OnButtonPressed(Object ^ parameter) { m_standardCalculatorManager.SendCommand(Command::CommandCLEAR); - if (!IsRecoverableCommand((int)numOpEnum)) + if (!IsRecoverableCommand(static_cast(numOpEnum))) { return; } @@ -620,7 +620,7 @@ void StandardCalculatorViewModel::OnButtonPressed(Object ^ parameter) && numOpEnum != NumbersAndOperatorsEnum::IsProgrammerMode && numOpEnum != NumbersAndOperatorsEnum::FToE && (numOpEnum != NumbersAndOperatorsEnum::Degree) && (numOpEnum != NumbersAndOperatorsEnum::Radians) && (numOpEnum != NumbersAndOperatorsEnum::Grads)) { - if (!m_keyPressed) + if (!m_KeyPressed) { SaveEditedCommand(m_selectedExpressionToken->TokenPosition, cmdenum); } @@ -673,49 +673,24 @@ void StandardCalculatorViewModel::OnButtonPressed(Object ^ parameter) m_isLastOperationHistoryLoad = false; } - TraceLogger::GetInstance().UpdateButtonUsage(numOpEnum, GetCalculatorMode()); + TraceLogger::GetInstance()->UpdateButtonUsage(numOpEnum, GetCalculatorMode()); m_standardCalculatorManager.SendCommand(cmdenum); } } } -int StandardCalculatorViewModel::GetBitLengthType() +RADIX_TYPE StandardCalculatorViewModel::GetRadixTypeFromNumberBase(NumberBase base) { - if (IsQwordEnabled) + switch (base) { - return QwordType; - } - else if (IsDwordEnabled) - { - return DwordType; - } - else if (IsWordEnabled) - { - return WordType; - } - else - { - return ByteType; - } -} - -int StandardCalculatorViewModel::GetNumberBase() -{ - if (CurrentRadixType == HEX_RADIX) - { - return HexBase; - } - else if (CurrentRadixType == DEC_RADIX) - { - return DecBase; - } - else if (CurrentRadixType == OCT_RADIX) - { - return OctBase; - } - else - { - return BinBase; + case NumberBase::BinBase: + return RADIX_TYPE::BIN_RADIX; + case NumberBase::HexBase: + return RADIX_TYPE::HEX_RADIX; + case NumberBase::OctBase: + return RADIX_TYPE::OCT_RADIX; + default: + return RADIX_TYPE::DEC_RADIX; } } @@ -723,15 +698,16 @@ void StandardCalculatorViewModel::OnCopyCommand(Object ^ parameter) { CopyPasteManager::CopyToClipboard(GetRawDisplayValue()); - String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::DisplayCopied); + String ^ announcement = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::DisplayCopied); Announcement = CalculatorAnnouncement::GetDisplayCopiedAnnouncement(announcement); } void StandardCalculatorViewModel::OnPasteCommand(Object ^ parameter) { + auto that(this); ViewMode mode; - int NumberBase = -1; - int bitLengthType = -1; + BitLength bitLengthType = BitLength::BitLengthUnknown; + NumberBase numberBase = NumberBase::Unknown; if (IsScientific) { mode = ViewMode::Scientific; @@ -739,8 +715,8 @@ void StandardCalculatorViewModel::OnPasteCommand(Object ^ parameter) else if (IsProgrammer) { mode = ViewMode::Programmer; - NumberBase = GetNumberBase(); - bitLengthType = GetBitLengthType(); + bitLengthType = m_valueBitLength; + numberBase = CurrentRadixType; } else { @@ -753,8 +729,8 @@ void StandardCalculatorViewModel::OnPasteCommand(Object ^ parameter) } // Ensure that the paste happens on the UI thread - CopyPasteManager::GetStringToPaste(mode, NavCategory::GetGroupType(mode), NumberBase, bitLengthType) - .then([this, mode](String ^ pastedString) { OnPaste(pastedString); }, concurrency::task_continuation_context::use_current()); + create_task(CopyPasteManager::GetStringToPaste(mode, NavCategory::GetGroupType(mode), numberBase, bitLengthType)) + .then([that, mode](String ^ pastedString) { that->OnPaste(pastedString); }, concurrency::task_continuation_context::use_current()); } CalculationManager::Command StandardCalculatorViewModel::ConvertToOperatorsEnum(NumbersAndOperatorsEnum operation) @@ -765,13 +741,13 @@ CalculationManager::Command StandardCalculatorViewModel::ConvertToOperatorsEnum( void StandardCalculatorViewModel::OnPaste(String ^ pastedString) { // If pastedString is invalid("NoOp") then display pasteError else process the string - if (pastedString == StringReference(CopyPasteManager::PasteErrorString)) + if (CopyPasteManager::IsErrorMessage(pastedString)) { this->DisplayPasteError(); return; } - TraceLogger::GetInstance().LogInputPasted(GetCalculatorMode()); + TraceLogger::GetInstance()->LogInputPasted(GetCalculatorMode()); bool isFirstLegalChar = true; m_standardCalculatorManager.SendCommand(Command::CommandCENTR); bool sendNegate = false; @@ -787,9 +763,10 @@ void StandardCalculatorViewModel::OnPaste(String ^ pastedString) while (it != pastedString->End()) { bool sendCommand = true; - bool canSendNegate = false; + auto buttonInfo = MapCharacterToButtonId(*it); - NumbersAndOperatorsEnum mappedNumOp = MapCharacterToButtonId(*it, canSendNegate); + NumbersAndOperatorsEnum mappedNumOp = buttonInfo.buttonId; + bool canSendNegate = buttonInfo.canSendNegate; if (mappedNumOp == NumbersAndOperatorsEnum::None) { @@ -891,7 +868,7 @@ void StandardCalculatorViewModel::OnPaste(String ^ pastedString) if (mappedNumOp == NumbersAndOperatorsEnum::Exp) { // Check the following item - switch (MapCharacterToButtonId(*(it + 1), canSendNegate)) + switch (MapCharacterToButtonId(*(it + 1)).buttonId) { case NumbersAndOperatorsEnum::Subtract: { @@ -917,10 +894,13 @@ void StandardCalculatorViewModel::OnClearMemoryCommand(Object ^ parameter) { m_standardCalculatorManager.MemorizedNumberClearAll(); - TraceLogger::GetInstance().UpdateButtonUsage(NumbersAndOperatorsEnum::MemoryClear, GetCalculatorMode()); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::MemoryClear, GetCalculatorMode()); - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement(CalculatorResourceKeys::MemoryCleared, m_localizedMemoryCleared); - Announcement = CalculatorAnnouncement::GetMemoryClearedAnnouncement(announcement); + if (m_localizedMemoryCleared == nullptr) + { + m_localizedMemoryCleared = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::MemoryCleared); + } + Announcement = CalculatorAnnouncement::GetMemoryClearedAnnouncement(m_localizedMemoryCleared); } void StandardCalculatorViewModel::OnPinUnpinCommand(Object ^ parameter) @@ -938,10 +918,11 @@ void StandardCalculatorViewModel::SetViewPinnedState(bool pinned) IsCurrentViewPinned = pinned; } -NumbersAndOperatorsEnum StandardCalculatorViewModel::MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate) +ButtonInfo StandardCalculatorViewModel::MapCharacterToButtonId(char16 ch) { - NumbersAndOperatorsEnum mappedValue = NumbersAndOperatorsEnum::None; - canSendNegate = false; + ButtonInfo result; + result.buttonId = NumbersAndOperatorsEnum::None; + result.canSendNegate = false; switch (ch) { @@ -955,107 +936,127 @@ NumbersAndOperatorsEnum StandardCalculatorViewModel::MapCharacterToButtonId(cons case '7': case '8': case '9': - mappedValue = NumbersAndOperatorsEnum::Zero + static_cast(ch - L'0'); - canSendNegate = true; + result.buttonId = NumbersAndOperatorsEnum::Zero + static_cast(ch - L'0'); + result.canSendNegate = true; break; case '*': - mappedValue = NumbersAndOperatorsEnum::Multiply; + result.buttonId = NumbersAndOperatorsEnum::Multiply; break; case '+': - mappedValue = NumbersAndOperatorsEnum::Add; + result.buttonId = NumbersAndOperatorsEnum::Add; break; case '-': - mappedValue = NumbersAndOperatorsEnum::Subtract; + result.buttonId = NumbersAndOperatorsEnum::Subtract; break; case '/': - mappedValue = NumbersAndOperatorsEnum::Divide; + result.buttonId = NumbersAndOperatorsEnum::Divide; + break; + + case '^': + if (IsScientific) + { + result.buttonId = NumbersAndOperatorsEnum::XPowerY; + } + break; + + case '%': + if (IsScientific || IsProgrammer) + { + result.buttonId = NumbersAndOperatorsEnum::Mod; + } break; case '=': - mappedValue = NumbersAndOperatorsEnum::Equals; + result.buttonId = NumbersAndOperatorsEnum::Equals; break; case '(': - mappedValue = NumbersAndOperatorsEnum::OpenParenthesis; + result.buttonId = NumbersAndOperatorsEnum::OpenParenthesis; break; case ')': - mappedValue = NumbersAndOperatorsEnum::CloseParenthesis; + result.buttonId = NumbersAndOperatorsEnum::CloseParenthesis; break; case 'a': case 'A': - mappedValue = NumbersAndOperatorsEnum::A; + result.buttonId = NumbersAndOperatorsEnum::A; break; case 'b': case 'B': - mappedValue = NumbersAndOperatorsEnum::B; + result.buttonId = NumbersAndOperatorsEnum::B; break; case 'c': case 'C': - mappedValue = NumbersAndOperatorsEnum::C; + result.buttonId = NumbersAndOperatorsEnum::C; break; case 'd': case 'D': - mappedValue = NumbersAndOperatorsEnum::D; + result.buttonId = NumbersAndOperatorsEnum::D; break; case 'e': case 'E': // Only allow scientific notation in scientific mode if (IsProgrammer) { - mappedValue = NumbersAndOperatorsEnum::E; + result.buttonId = NumbersAndOperatorsEnum::E; } else { - mappedValue = NumbersAndOperatorsEnum::Exp; + result.buttonId = NumbersAndOperatorsEnum::Exp; } break; case 'f': case 'F': - mappedValue = NumbersAndOperatorsEnum::F; + result.buttonId = NumbersAndOperatorsEnum::F; break; default: // For the decimalSeparator, we need to respect the user setting. if (ch == m_decimalSeparator) { - mappedValue = NumbersAndOperatorsEnum::Decimal; + result.buttonId = NumbersAndOperatorsEnum::Decimal; } break; } - if (mappedValue == NumbersAndOperatorsEnum::None) + if (result.buttonId == NumbersAndOperatorsEnum::None) { if (LocalizationSettings::GetInstance().IsLocalizedDigit(ch)) { - mappedValue = - NumbersAndOperatorsEnum::Zero + static_cast(ch - LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit('0')); - canSendNegate = true; + result.buttonId = NumbersAndOperatorsEnum::Zero + + static_cast(ch - LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit('0')); + result.canSendNegate = true; } } // Negate cannot be sent for leading zeroes - if (NumbersAndOperatorsEnum::Zero == mappedValue) + if (NumbersAndOperatorsEnum::Zero == result.buttonId) { - canSendNegate = false; + result.canSendNegate = false; } - return mappedValue; + return result; +} +void StandardCalculatorViewModel::OnInputChanged() +{ + IsInputEmpty = m_standardCalculatorManager.IsInputEmpty(); } void StandardCalculatorViewModel::OnMemoryButtonPressed() { m_standardCalculatorManager.MemorizeNumber(); - TraceLogger::GetInstance().UpdateButtonUsage(NumbersAndOperatorsEnum::Memory, GetCalculatorMode()); - - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MemorySave, m_localizedMemorySavedAutomationFormat, m_DisplayValue->Data()); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::Memory, GetCalculatorMode()); + if (m_localizedMemorySavedAutomationFormat == nullptr) + { + m_localizedMemorySavedAutomationFormat = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::MemorySave); + } + String ^ announcement = LocalizationStringUtil::GetLocalizedString(m_localizedMemorySavedAutomationFormat, m_DisplayValue); Announcement = CalculatorAnnouncement::GetMemoryItemAddedAnnouncement(announcement); } @@ -1069,9 +1070,12 @@ void StandardCalculatorViewModel::OnMemoryItemChanged(unsigned int indexOfMemory wstring localizedIndex = to_wstring(indexOfMemory + 1); LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedIndex); - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MemoryItemChanged, m_localizedMemoryItemChangedAutomationFormat, localizedIndex.c_str(), localizedValue->Data()); - + if (m_localizedMemoryItemChangedAutomationFormat == nullptr) + { + m_localizedMemoryItemChangedAutomationFormat = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::MemoryItemChanged); + } + String ^ announcement = + LocalizationStringUtil::GetLocalizedString(m_localizedMemoryItemChangedAutomationFormat, StringReference(localizedIndex.c_str()), localizedValue); Announcement = CalculatorAnnouncement::GetMemoryItemChangedAnnouncement(announcement); } } @@ -1085,7 +1089,7 @@ void StandardCalculatorViewModel::OnMemoryItemPressed(Object ^ memoryItemPositio HideMemoryClicked(); auto mode = IsStandard ? ViewMode::Standard : IsScientific ? ViewMode::Scientific : ViewMode::Programmer; - TraceLogger::GetInstance().LogMemoryItemLoad(mode, MemorizedNumbers->Size, boxedPosition->Value); + TraceLogger::GetInstance()->LogMemoryItemLoad(mode, MemorizedNumbers->Size, boxedPosition->Value); } } @@ -1096,7 +1100,7 @@ void StandardCalculatorViewModel::OnMemoryAdd(Object ^ memoryItemPosition) if (MemorizedNumbers) { auto boxedPosition = safe_cast ^>(memoryItemPosition); - TraceLogger::GetInstance().UpdateButtonUsage(NumbersAndOperatorsEnum::MemoryAdd, GetCalculatorMode()); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::MemoryAdd, GetCalculatorMode()); m_standardCalculatorManager.MemorizedNumberAdd(boxedPosition->Value); } } @@ -1107,7 +1111,7 @@ void StandardCalculatorViewModel::OnMemorySubtract(Object ^ memoryItemPosition) if (MemorizedNumbers) { auto boxedPosition = safe_cast ^>(memoryItemPosition); - TraceLogger::GetInstance().UpdateButtonUsage(NumbersAndOperatorsEnum::MemorySubtract, GetCalculatorMode()); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::MemorySubtract, GetCalculatorMode()); m_standardCalculatorManager.MemorizedNumberSubtract(boxedPosition->Value); } } @@ -1133,13 +1137,17 @@ void StandardCalculatorViewModel::OnMemoryClear(_In_ Object ^ memoryItemPosition { IsMemoryEmpty = true; } - TraceLogger::GetInstance().UpdateButtonUsage(NumbersAndOperatorsEnum::MemoryClear, GetCalculatorMode()); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::MemoryClear, GetCalculatorMode()); wstring localizedIndex = to_wstring(boxedPosition->Value + 1); LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedIndex); - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MemoryItemCleared, m_localizedMemoryItemClearedAutomationFormat, localizedIndex.c_str()); + if (m_localizedMemoryItemClearedAutomationFormat == nullptr) + { + m_localizedMemoryItemClearedAutomationFormat = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::MemoryItemCleared); + } + String ^ announcement = + LocalizationStringUtil::GetLocalizedString(m_localizedMemoryItemClearedAutomationFormat, StringReference(localizedIndex.c_str())); Announcement = CalculatorAnnouncement::GetMemoryClearedAnnouncement(announcement); } @@ -1176,7 +1184,7 @@ void StandardCalculatorViewModel::OnPropertyChanged(String ^ propertyname) } else if (propertyname == IsBitFlipCheckedPropertyName) { - TraceLogger::GetInstance().UpdateButtonUsage( + TraceLogger::GetInstance()->UpdateButtonUsage( IsBitFlipChecked ? NumbersAndOperatorsEnum::BitflipButton : NumbersAndOperatorsEnum::FullKeypadButton, ViewMode::Programmer); } } @@ -1219,9 +1227,7 @@ String ^ StandardCalculatorViewModel::GetRawDisplayValue() } else { - wstring rawValue; - LocalizationSettings::GetInstance().RemoveGroupSeparators(DisplayValue->Data(), DisplayValue->Length(), &rawValue); - return ref new String(rawValue.c_str()); + return LocalizationSettings::GetInstance().RemoveGroupSeparators(DisplayValue); } } @@ -1230,16 +1236,14 @@ String ^ StandardCalculatorViewModel::GetRawDisplayValue() // 'displayValue' is a localized string containing a numerical value to be displayed to the user. String ^ StandardCalculatorViewModel::GetLocalizedStringFormat(String ^ format, String ^ displayValue) { - String ^ localizedString = ref new String(LocalizationStringUtil::GetLocalizedString(format->Data(), displayValue->Data()).c_str()); - return localizedString; + return LocalizationStringUtil::GetLocalizedString(format, displayValue); } void StandardCalculatorViewModel::ResetDisplay() { AreHEXButtonsEnabled = false; - CurrentRadixType = (int)RADIX_TYPE::DEC_RADIX; + CurrentRadixType = NumberBase::DecBase; m_standardCalculatorManager.SetRadix(DEC_RADIX); - ProgModeRadixChange(); } void StandardCalculatorViewModel::SetPrecision(int32_t precision) @@ -1247,17 +1251,16 @@ void StandardCalculatorViewModel::SetPrecision(int32_t precision) m_standardCalculatorManager.SetPrecision(precision); } -void StandardCalculatorViewModel::SwitchProgrammerModeBase(RADIX_TYPE radixType) +void StandardCalculatorViewModel::SwitchProgrammerModeBase(NumberBase numberBase) { if (IsInError) { m_standardCalculatorManager.SendCommand(Command::CommandCLEAR); } - AreHEXButtonsEnabled = (radixType == RADIX_TYPE::HEX_RADIX); - CurrentRadixType = (int)radixType; - m_standardCalculatorManager.SetRadix(radixType); - ProgModeRadixChange(); + AreHEXButtonsEnabled = numberBase == NumberBase::HexBase; + CurrentRadixType = numberBase; + m_standardCalculatorManager.SetRadix(GetRadixTypeFromNumberBase(numberBase)); } void StandardCalculatorViewModel::SetMemorizedNumbersString() @@ -1282,72 +1285,66 @@ ANGLE_TYPE GetAngleTypeFromCommand(Command command) void StandardCalculatorViewModel::SaveEditedCommand(_In_ unsigned int tokenPosition, _In_ Command command) { - pair token; bool handleOperand = false; - int nOpCode = static_cast(command); - wstring updatedToken = L""; + wstring updatedToken; - shared_ptr tokenCommand; - IFTPlatformException(m_tokens->GetAt(tokenPosition, &token)); + const pair& token = m_tokens->at(tokenPosition); + const shared_ptr& tokenCommand = m_commands->at(token.second); - unsigned int tokenCommandIndex = token.second; - IFTPlatformException(m_commands->GetAt(tokenCommandIndex, &tokenCommand)); - - if (IsUnaryOp(nOpCode) && command != Command::CommandSIGN) + if (IsUnaryOp(command) && command != Command::CommandSIGN) { int angleCmd = static_cast(m_standardCalculatorManager.GetCurrentDegreeMode()); ANGLE_TYPE angleType = GetAngleTypeFromCommand(static_cast(angleCmd)); - if (IsTrigOp(nOpCode)) + if (IsTrigOp(command)) { shared_ptr spUnaryCommand = dynamic_pointer_cast(tokenCommand); - spUnaryCommand->SetCommands(angleCmd, nOpCode); + spUnaryCommand->SetCommands(angleCmd, static_cast(command)); } else { shared_ptr spUnaryCommand = dynamic_pointer_cast(tokenCommand); - spUnaryCommand->SetCommand(nOpCode); + spUnaryCommand->SetCommand(static_cast(command)); } - switch (nOpCode) + switch (command) { - case static_cast(Command::CommandASIN): + case Command::CommandASIN: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSIN), true, angleType); break; - case static_cast(Command::CommandACOS): + case Command::CommandACOS: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOS), true, angleType); break; - case static_cast(Command::CommandATAN): + case Command::CommandATAN: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTAN), true, angleType); break; - case static_cast(Command::CommandASINH): + case Command::CommandASINH: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandSINH), true, angleType); break; - case static_cast(Command::CommandACOSH): + case Command::CommandACOSH: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandCOSH), true, angleType); break; - case static_cast(Command::CommandATANH): + case Command::CommandATANH: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandTANH), true, angleType); break; - case static_cast(Command::CommandPOWE): + case Command::CommandPOWE: updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(Command::CommandLN), true, angleType); break; default: - updatedToken = CCalcEngine::OpCodeToUnaryString(nOpCode, false, angleType); + updatedToken = CCalcEngine::OpCodeToUnaryString(static_cast(command), false, angleType); } if ((token.first.length() > 0) && (token.first[token.first.length() - 1] == L'(')) { - wstring chOpenBrace = L"("; - updatedToken.append(chOpenBrace); + updatedToken += L'('; } } - else if (IsBinOp(nOpCode)) + else if (IsBinOp(command)) { shared_ptr spBinaryCommand = dynamic_pointer_cast(tokenCommand); - spBinaryCommand->SetCommand(nOpCode); - updatedToken = CCalcEngine::OpCodeToString(nOpCode); + spBinaryCommand->SetCommand(static_cast(command)); + updatedToken = CCalcEngine::OpCodeToString(static_cast(command)); } - else if (IsOpnd(nOpCode) || command == Command::CommandBACK) + else if (IsOpnd(command) || command == Command::CommandBACK) { HandleUpdatedOperandData(command); handleOperand = true; @@ -1356,8 +1353,8 @@ void StandardCalculatorViewModel::SaveEditedCommand(_In_ unsigned int tokenPosit { if (tokenCommand->GetCommandType() == CommandType::UnaryCommand) { - shared_ptr spSignCommand = make_shared(nOpCode); - IFTPlatformException(m_commands->InsertAt(tokenCommandIndex + 1, spSignCommand)); + shared_ptr spSignCommand = make_shared(static_cast(command)); + m_commands->insert(m_commands->begin() + token.second + 1, spSignCommand); } else { @@ -1370,12 +1367,8 @@ void StandardCalculatorViewModel::SaveEditedCommand(_In_ unsigned int tokenPosit if (!handleOperand) { - IFTPlatformException(m_commands->SetAt(tokenCommandIndex, tokenCommand)); - - pair selectedToken; - IFTPlatformException(m_tokens->GetAt(tokenPosition, &selectedToken)); - selectedToken.first = updatedToken; - IFTPlatformException(m_tokens->SetAt(tokenPosition, selectedToken)); + (*m_commands)[token.second] = tokenCommand; + (*m_tokens)[tokenPosition].first = updatedToken; DisplayExpressionToken ^ displayExpressionToken = ExpressionTokens->GetAt(tokenPosition); displayExpressionToken->Token = ref new Platform::String(updatedToken.c_str()); @@ -1393,30 +1386,21 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory) { // Recalculate Command currentDegreeMode = m_standardCalculatorManager.GetCurrentDegreeMode(); - shared_ptr>> savedCommands = make_shared>>(); - + shared_ptr>> savedCommands = make_shared>>(); vector currentCommands; - unsigned int commandListCount; - m_commands->GetSize(&commandListCount); - for (unsigned int i = 0; i < commandListCount; i++) - { - shared_ptr command; - IFTPlatformException(m_commands->GetAt(i, &command)); - savedCommands->Append(command); + for (const auto& command : *m_commands) + { + savedCommands->push_back(command); CommandType commandType = command->GetCommandType(); if (commandType == CommandType::UnaryCommand) { shared_ptr spCommand = dynamic_pointer_cast(command); - shared_ptr> unaryCommands = spCommand->GetCommands(); - unsigned int unaryCommandCount; - unaryCommands->GetSize(&unaryCommandCount); + const shared_ptr>& unaryCommands = spCommand->GetCommands(); - int nUCode; - for (unsigned int j = 0; j < unaryCommandCount; ++j) + for (int nUCode : *unaryCommands) { - IFTPlatformException(unaryCommands->GetAt(j, &nUCode)); currentCommands.push_back(nUCode); } } @@ -1436,15 +1420,11 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory) if (commandType == CommandType::OperandCommand) { shared_ptr spCommand = dynamic_pointer_cast(command); - shared_ptr> opndCommands = spCommand->GetCommands(); - unsigned int opndCommandCount; - opndCommands->GetSize(&opndCommandCount); + const shared_ptr>& opndCommands = spCommand->GetCommands(); bool fNeedIDCSign = spCommand->IsNegative(); - int nOCode; - for (unsigned int j = 0; j < opndCommandCount; ++j) + for (int nOCode : *opndCommands) { - IFTPlatformException(opndCommands->GetAt(j, &nOCode)); currentCommands.push_back(nOCode); if (fNeedIDCSign && nOCode != IDC_0) @@ -1455,16 +1435,12 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory) } } } - shared_ptr>> savedTokens = make_shared>>(); - unsigned int tokenCount; - IFTPlatformException(m_tokens->GetSize(&tokenCount)); + shared_ptr>> savedTokens = make_shared>>(); - for (unsigned int i = 0; i < tokenCount; ++i) + for (const auto& currentToken : *m_tokens) { - pair currentToken; - IFTPlatformException(m_tokens->GetAt(i, ¤tToken)); - savedTokens->Append(currentToken); + savedTokens->push_back(currentToken); } m_standardCalculatorManager.Reset(false); @@ -1479,10 +1455,10 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory) } m_standardCalculatorManager.SendCommand(currentDegreeMode); - size_t currentCommandsSize = currentCommands.size(); - for (size_t i = 0; i < currentCommandsSize; i++) + + for (int command : currentCommands) { - m_standardCalculatorManager.SendCommand(static_cast(currentCommands[i])); + m_standardCalculatorManager.SendCommand(static_cast(command)); } if (fromHistory) // This is for the cases where the expression is loaded from history @@ -1502,47 +1478,34 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory) CommandType StandardCalculatorViewModel::GetSelectedTokenType(_In_ unsigned int tokenPosition) { - pair token; - shared_ptr tokenCommand; - IFTPlatformException(m_tokens->GetAt(tokenPosition, &token)); - + const pair& token = m_tokens->at(tokenPosition); unsigned int tokenCommandIndex = token.second; - IFTPlatformException(m_commands->GetAt(tokenCommandIndex, &tokenCommand)); + const shared_ptr& tokenCommand = m_commands->at(tokenCommandIndex); return tokenCommand->GetCommandType(); } -bool StandardCalculatorViewModel::IsOpnd(int nOpCode) +bool StandardCalculatorViewModel::IsOpnd(Command command) { - static Command opnd[] = { Command::Command0, Command::Command1, Command::Command2, Command::Command3, Command::Command4, Command::Command5, + static constexpr Command opnd[] = { Command::Command0, Command::Command1, Command::Command2, Command::Command3, Command::Command4, Command::Command5, Command::Command6, Command::Command7, Command::Command8, Command::Command9, Command::CommandPNT }; - for (unsigned int i = 0; i < size(opnd); i++) - { - if (nOpCode == static_cast(opnd[i])) - { - return true; - } - } - return false; + return find(begin(opnd), end(opnd), command) != end(opnd); } -bool StandardCalculatorViewModel::IsUnaryOp(int nOpCode) +bool StandardCalculatorViewModel::IsUnaryOp(Command command) { - static Command unaryOp[] = { Command::CommandSQRT, Command::CommandFAC, Command::CommandSQR, Command::CommandLOG, + static constexpr Command unaryOp[] = { Command::CommandSQRT, Command::CommandFAC, Command::CommandSQR, Command::CommandLOG, Command::CommandPOW10, Command::CommandPOWE, Command::CommandLN, Command::CommandREC, Command::CommandSIGN, Command::CommandSINH, Command::CommandASINH, Command::CommandCOSH, Command::CommandACOSH, Command::CommandTANH, Command::CommandATANH, Command::CommandCUB }; - for (unsigned int i = 0; i < size(unaryOp); i++) + if (find(begin(unaryOp), end(unaryOp), command) != end(unaryOp)) { - if (nOpCode == static_cast(unaryOp[i])) - { - return true; - } + return true; } - if (IsTrigOp(nOpCode)) + if (IsTrigOp(command)) { return true; } @@ -1550,80 +1513,50 @@ bool StandardCalculatorViewModel::IsUnaryOp(int nOpCode) return false; } -bool StandardCalculatorViewModel::IsTrigOp(int nOpCode) +bool StandardCalculatorViewModel::IsTrigOp(Command command) { - static Command trigOp[] = { + static constexpr Command trigOp[] = { Command::CommandSIN, Command::CommandCOS, Command::CommandTAN, Command::CommandASIN, Command::CommandACOS, Command::CommandATAN }; - for (unsigned int i = 0; i < size(trigOp); i++) - { - if (nOpCode == static_cast(trigOp[i])) - { - return true; - } - } - return false; + return find(begin(trigOp), end(trigOp), command) != end(trigOp); } -bool StandardCalculatorViewModel::IsBinOp(int nOpCode) +bool StandardCalculatorViewModel::IsBinOp(Command command) { - static Command binOp[] = { Command::CommandADD, Command::CommandSUB, Command::CommandMUL, Command::CommandDIV, + static constexpr Command binOp[] = { Command::CommandADD, Command::CommandSUB, Command::CommandMUL, Command::CommandDIV, Command::CommandEXP, Command::CommandROOT, Command::CommandMOD, Command::CommandPWR }; - for (unsigned int i = 0; i < size(binOp); i++) - { - if (nOpCode == static_cast(binOp[i])) - { - return true; - } - } - return false; + return find(begin(binOp), end(binOp), command) != end(binOp); } -bool StandardCalculatorViewModel::IsRecoverableCommand(int nOpCode) +bool StandardCalculatorViewModel::IsRecoverableCommand(Command command) { - if (IsOpnd(nOpCode)) + if (IsOpnd(command)) { return true; } // Programmer mode, bit flipping - int minBinPos = static_cast(Command::CommandBINEDITSTART); - int maxBinPos = static_cast(Command::CommandBINEDITEND); - if (minBinPos <= nOpCode && nOpCode <= maxBinPos) + if (Command::CommandBINEDITSTART <= command && command <= Command::CommandBINEDITEND) { return true; } - static Command recoverableCommands[] = { Command::CommandA, Command::CommandB, Command::CommandC, Command::CommandD, Command::CommandE, Command::CommandF }; + static constexpr Command recoverableCommands[] = { Command::CommandA, Command::CommandB, Command::CommandC, + Command::CommandD, Command::CommandE, Command::CommandF }; - for (unsigned int i = 0; i < size(recoverableCommands); i++) - { - if (nOpCode == static_cast(recoverableCommands[i])) - { - return true; - } - } - return false; + return find(begin(recoverableCommands), end(recoverableCommands), command) != end(recoverableCommands); } size_t StandardCalculatorViewModel::LengthWithoutPadding(wstring str) { - size_t count = 0; - for (size_t i = 0; i < str.length(); i++) - { - if (str[i] != L' ') - { - count++; - } - } - return count; + return str.length() - count(str.begin(), str.end(), L' '); } wstring StandardCalculatorViewModel::AddPadding(wstring binaryString) { - if (LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(binaryString) == L"0") + if (LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(StringReference(binaryString.c_str())) == L"0") { return binaryString; } @@ -1632,16 +1565,12 @@ wstring StandardCalculatorViewModel::AddPadding(wstring binaryString) { pad = 0; } - wstring padString = L""; - for (size_t i = 0; i < pad; i++) - { - padString += L"0"; - } - return padString + binaryString; + return wstring(pad, L'0') + binaryString; } void StandardCalculatorViewModel::UpdateProgrammerPanelDisplay() { + constexpr int32_t precision = 64; wstring hexDisplayString; wstring decimalDisplayString; wstring octalDisplayString; @@ -1649,8 +1578,7 @@ void StandardCalculatorViewModel::UpdateProgrammerPanelDisplay() if (!IsInError) { // we want the precision to be set to maximum value so that the autoconversions result as desired - int32_t precision = 64; - if (m_standardCalculatorManager.GetResultForRadix(16, precision) == L"") + if ((hexDisplayString = m_standardCalculatorManager.GetResultForRadix(16, precision, true)) == L"") { hexDisplayString = DisplayValue->Data(); decimalDisplayString = DisplayValue->Data(); @@ -1659,10 +1587,9 @@ void StandardCalculatorViewModel::UpdateProgrammerPanelDisplay() } else { - hexDisplayString = m_standardCalculatorManager.GetResultForRadix(16, precision); - decimalDisplayString = m_standardCalculatorManager.GetResultForRadix(10, precision); - octalDisplayString = m_standardCalculatorManager.GetResultForRadix(8, precision); - binaryDisplayString = m_standardCalculatorManager.GetResultForRadix(2, precision); + decimalDisplayString = m_standardCalculatorManager.GetResultForRadix(10, precision, true); + octalDisplayString = m_standardCalculatorManager.GetResultForRadix(8, precision, true); + binaryDisplayString = m_standardCalculatorManager.GetResultForRadix(2, precision, true); } } const auto& localizer = LocalizationSettings::GetInstance(); @@ -1681,6 +1608,17 @@ void StandardCalculatorViewModel::UpdateProgrammerPanelDisplay() DecDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedDecimalAutomationFormat, DecimalDisplayValue); OctDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedOctalAutomationFormat, GetNarratorStringReadRawNumbers(OctalDisplayValue)); BinDisplayValue_AutomationName = GetLocalizedStringFormat(m_localizedBinaryAutomationFormat, GetNarratorStringReadRawNumbers(BinaryDisplayValue)); + + auto binaryValueArray = ref new Vector(64, false); + auto binaryValue = m_standardCalculatorManager.GetResultForRadix(2, precision, false); + int i = 0; + + // To get bit 0, grab from opposite end of string. + for (std::wstring::reverse_iterator it = binaryValue.rbegin(); it != binaryValue.rend(); ++it) + { + binaryValueArray->SetAt(i++, *it == L'1'); + } + BinaryDigits = binaryValueArray; } void StandardCalculatorViewModel::SwitchAngleType(NumbersAndOperatorsEnum num) @@ -1710,20 +1648,18 @@ NumbersAndOperatorsEnum StandardCalculatorViewModel::ConvertIntegerToNumbersAndO void StandardCalculatorViewModel::UpdateOperand(int pos, String ^ text) { - pair p; - m_tokens->GetAt(pos, &p); + pair p = m_tokens->at(pos); - String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(text->Data()); + String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(text); p.first = englishString->Data(); int commandPos = p.second; - shared_ptr exprCmd; - m_commands->GetAt(commandPos, &exprCmd); + const shared_ptr& exprCmd = m_commands->at(commandPos); auto operandCommand = std::dynamic_pointer_cast(exprCmd); if (operandCommand != nullptr) { - shared_ptr> commands = make_shared>(); + shared_ptr> commands = make_shared>(); size_t length = p.first.length(); if (length > 0) { @@ -1761,33 +1697,29 @@ void StandardCalculatorViewModel::UpdateOperand(int pos, String ^ text) continue; } } - commands->Append(num); + commands->push_back(num); } } else { - commands->Append(0); + commands->push_back(0); } operandCommand->SetCommands(commands); } } -void StandardCalculatorViewModel::UpdatecommandsInRecordingMode() +void StandardCalculatorViewModel::UpdateCommandsInRecordingMode() { - vector savedCommands = m_standardCalculatorManager.GetSavedCommands(); - shared_ptr> commands = make_shared>(); + shared_ptr> commands = make_shared>(); bool isDecimal = false; bool isNegative = false; bool isExpMode = false; bool ePlusMode = false; bool eMinusMode = false; - int num = 0; - Command val; - for (unsigned int i = 0; i < savedCommands.size(); ++i) + for (const auto savedCommand : m_standardCalculatorManager.GetSavedCommands()) { - val = safe_cast(savedCommands[i]); - num = static_cast(val); + const Command val = static_cast(savedCommand); if (val == Command::CommandSIGN) { isNegative = true; @@ -1822,27 +1754,27 @@ void StandardCalculatorViewModel::UpdatecommandsInRecordingMode() isExpMode = false; ePlusMode = false; eMinusMode = false; - commands->Clear(); + commands->clear(); continue; } - commands->Append(num); + commands->push_back(static_cast(val)); } - unsigned int size = 0; - commands->GetSize(&size); - if (size > 0) + if (!commands->empty()) { shared_ptr sp = make_shared(commands, isNegative, isDecimal, isExpMode); - m_commands->Append(sp); + m_commands->push_back(sp); } Recalculate(); } void StandardCalculatorViewModel::OnMaxDigitsReached() { - String ^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::MaxDigitsReachedFormat, m_localizedMaxDigitsReachedAutomationFormat, m_CalculationResultAutomationName->Data()); - + if (m_localizedMaxDigitsReachedAutomationFormat == nullptr) + { + m_localizedMaxDigitsReachedAutomationFormat = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::MaxDigitsReachedFormat); + } + String ^ announcement = LocalizationStringUtil::GetLocalizedString(m_localizedMaxDigitsReachedAutomationFormat, m_CalculationResultAutomationName); Announcement = CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(announcement); } @@ -1860,11 +1792,14 @@ NarratorAnnouncement ^ StandardCalculatorViewModel::GetDisplayUpdatedNarratorAnn } else { - announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( - CalculatorResourceKeys::ButtonPressFeedbackFormat, + if (m_localizedButtonPressFeedbackAutomationFormat == nullptr) + { + m_localizedButtonPressFeedbackAutomationFormat = AppResourceProvider::GetInstance()->GetResourceString(CalculatorResourceKeys::ButtonPressFeedbackFormat); + } + announcement = LocalizationStringUtil::GetLocalizedString( m_localizedButtonPressFeedbackAutomationFormat, - m_CalculationResultAutomationName->Data(), - m_feedbackForButtonPress->Data()); + m_CalculationResultAutomationName, + m_feedbackForButtonPress); } // Make sure we don't accidentally repeat an announcement. @@ -1885,3 +1820,39 @@ ViewMode StandardCalculatorViewModel::GetCalculatorMode() } return ViewMode::Programmer; } + +void StandardCalculatorViewModel::ValueBitLength::set(CalculatorApp::Common::BitLength value) +{ + if (m_valueBitLength != value) + { + m_valueBitLength = value; + RaisePropertyChanged(L"ValueBitLength"); + + switch (value) + { + case BitLength::BitLengthQWord: + ButtonPressed->Execute(NumbersAndOperatorsEnum::Qword); + break; + case BitLength::BitLengthDWord: + ButtonPressed->Execute(NumbersAndOperatorsEnum::Dword); + break; + case BitLength::BitLengthWord: + ButtonPressed->Execute(NumbersAndOperatorsEnum::Word); + break; + case BitLength::BitLengthByte: + ButtonPressed->Execute(NumbersAndOperatorsEnum::Byte); + break; + } + + // update memory list according to bit length + SetMemorizedNumbersString(); + } +} + +void StandardCalculatorViewModel::SelectHistoryItem(HistoryItemViewModel ^ item) +{ + SetHistoryExpressionDisplay(item->GetTokens(), item->GetCommands()); + SetExpressionDisplay(item->GetTokens(), item->GetCommands()); + SetPrimaryDisplay(item->Result, false); + IsFToEEnabled = false; +} diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h index 350155dd..909e32c9 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.h +++ b/src/CalcViewModel/StandardCalculatorViewModel.h @@ -9,6 +9,8 @@ #include "Common/CalculatorButtonUser.h" #include "HistoryViewModel.h" #include "MemoryItemViewModel.h" +#include "Common/BitLength.h" +#include "Common/NumberBase.h" namespace CalculatorFunctionalTests { @@ -18,7 +20,6 @@ namespace CalculatorFunctionalTests namespace CalculatorUnitTests { class MultiWindowUnitTests; - class TimerTests; } namespace CalculatorApp @@ -29,59 +30,63 @@ namespace CalculatorApp namespace ViewModel { #define ASCII_0 48 - public - delegate void HideMemoryClickedHandler(); - public - delegate void ProgModeRadixChangeHandler(); + public delegate void HideMemoryClickedHandler(); + + public value struct ButtonInfo + { + NumbersAndOperatorsEnum buttonId; + bool canSendNegate; + }; [Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged { public: StandardCalculatorViewModel(); void UpdateOperand(int pos, Platform::String ^ text); - void UpdatecommandsInRecordingMode(); - int GetBitLengthType(); - int GetNumberBase(); + void UpdateCommandsInRecordingMode(); OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); OBSERVABLE_PROPERTY_RW(Platform::String ^, DisplayValue); - OBSERVABLE_PROPERTY_RW(HistoryViewModel ^, HistoryVM); - OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError); - OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DisplayStringExpression); + OBSERVABLE_PROPERTY_R(HistoryViewModel ^, HistoryVM); + OBSERVABLE_PROPERTY_RW(bool, IsAlwaysOnTop); + OBSERVABLE_PROPERTY_R(bool, IsBinaryBitFlippingEnabled); + PROPERTY_R(bool, IsOperandUpdatedUsingViewModel); + PROPERTY_R(int, TokenPosition); + PROPERTY_R(bool, IsOperandTextCompletelySelected); + PROPERTY_R(bool, KeyPressed); + PROPERTY_R(Platform::String ^, SelectedExpressionLastData); + OBSERVABLE_NAMED_PROPERTY_R(bool, IsInError); + OBSERVABLE_PROPERTY_R(bool, IsOperatorCommand); OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, ExpressionTokens); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DecimalDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String ^, HexDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String ^, OctalDisplayValue); - OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, BinaryDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String ^, HexDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, DecDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, OctDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, BinDisplayValue_AutomationName); - OBSERVABLE_PROPERTY_RW(bool, IsBinaryOperatorEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsUnaryOperatorEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsNegateEnabled); + OBSERVABLE_PROPERTY_R(Platform::String ^, DecimalDisplayValue); + OBSERVABLE_PROPERTY_R(Platform::String ^, HexDisplayValue); + OBSERVABLE_PROPERTY_R(Platform::String ^, OctalDisplayValue); + OBSERVABLE_NAMED_PROPERTY_R(Platform::String ^, BinaryDisplayValue); + OBSERVABLE_NAMED_PROPERTY_R(Windows::Foundation::Collections::IVector ^, BinaryDigits); + OBSERVABLE_PROPERTY_R(Platform::String ^, HexDisplayValue_AutomationName); + OBSERVABLE_PROPERTY_R(Platform::String ^, DecDisplayValue_AutomationName); + OBSERVABLE_PROPERTY_R(Platform::String ^, OctDisplayValue_AutomationName); + OBSERVABLE_PROPERTY_R(Platform::String ^, BinDisplayValue_AutomationName); + OBSERVABLE_PROPERTY_R(bool, IsBinaryOperatorEnabled); + OBSERVABLE_PROPERTY_R(bool, IsUnaryOperatorEnabled); + OBSERVABLE_PROPERTY_R(bool, IsNegateEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsCurrentViewPinned); - OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector ^, MemorizedNumbers); + OBSERVABLE_PROPERTY_R(bool, IsCurrentViewPinned); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IVector ^, MemorizedNumbers); OBSERVABLE_NAMED_PROPERTY_RW(bool, IsMemoryEmpty); - OBSERVABLE_PROPERTY_RW(bool, IsFToEChecked); - OBSERVABLE_PROPERTY_RW(bool, IsFToEEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsHyperbolicChecked); - OBSERVABLE_PROPERTY_RW(bool, AreHEXButtonsEnabled); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CalculationResultAutomationName); - OBSERVABLE_PROPERTY_RW(Platform::String ^, CalculationExpressionAutomationName); - OBSERVABLE_PROPERTY_RW(bool, IsShiftProgrammerChecked); - OBSERVABLE_PROPERTY_RW(bool, IsQwordEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsDwordEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsWordEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsByteEnabled); - OBSERVABLE_PROPERTY_RW(int, CurrentRadixType); - OBSERVABLE_PROPERTY_RW(bool, AreTokensUpdated); - OBSERVABLE_PROPERTY_RW(bool, AreAlwaysOnTopResultsUpdated); + OBSERVABLE_PROPERTY_R(bool, IsFToEChecked); + OBSERVABLE_PROPERTY_R(bool, IsFToEEnabled); + OBSERVABLE_PROPERTY_R(bool, AreHEXButtonsEnabled); + OBSERVABLE_PROPERTY_R(Platform::String ^, CalculationResultAutomationName); + OBSERVABLE_PROPERTY_R(Platform::String ^, CalculationExpressionAutomationName); + OBSERVABLE_PROPERTY_R(bool, IsShiftProgrammerChecked); + OBSERVABLE_PROPERTY_R(CalculatorApp::Common::NumberBase, CurrentRadixType); + OBSERVABLE_PROPERTY_R(bool, AreTokensUpdated); + OBSERVABLE_PROPERTY_R(bool, AreAlwaysOnTopResultsUpdated); OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled); - OBSERVABLE_PROPERTY_RW(bool, AreProgrammerRadixOperatorsEnabled); - OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement ^, Announcement); + OBSERVABLE_PROPERTY_R(bool, AreProgrammerRadixOperatorsEnabled); + OBSERVABLE_PROPERTY_R(bool, IsInputEmpty); + OBSERVABLE_PROPERTY_R(CalculatorApp::Common::Automation::NarratorAnnouncement ^, Announcement); OBSERVABLE_PROPERTY_R(unsigned int, OpenParenthesisCount); COMMAND_FOR_METHOD(CopyCommand, StandardCalculatorViewModel::OnCopyCommand); @@ -93,23 +98,6 @@ namespace CalculatorApp COMMAND_FOR_METHOD(MemorySubtract, StandardCalculatorViewModel::OnMemorySubtract); event HideMemoryClickedHandler ^ HideMemoryClicked; - event ProgModeRadixChangeHandler ^ ProgModeRadixChange; - - property bool IsShiftChecked - { - bool get() - { - return m_isShiftChecked; - } - void set(bool value) - { - if (m_isShiftChecked != value) - { - m_isShiftChecked = value; - RaisePropertyChanged(L"IsShiftChecked"); - } - } - } property bool IsBitFlipChecked { @@ -128,21 +116,16 @@ namespace CalculatorApp } } } + static property Platform::String + ^ IsBitFlipCheckedPropertyName { Platform::String ^ get() { return Platform::StringReference(L"IsBitFlipChecked"); } } - property bool IsBinaryBitFlippingEnabled + property CalculatorApp::Common::BitLength ValueBitLength { - bool get() + CalculatorApp::Common::BitLength get() { - return m_isBinaryBitFlippingEnabled; - } - void set(bool value) - { - if (m_isBinaryBitFlippingEnabled != value) - { - m_isBinaryBitFlippingEnabled = value; - RaisePropertyChanged(L"IsBinaryBitFlippingEnabled"); - } + return m_valueBitLength; } + void set(CalculatorApp::Common::BitLength value); } property bool IsStandard @@ -213,22 +196,8 @@ namespace CalculatorApp } } } - - property bool IsAlwaysOnTop - { - bool get() - { - return m_isAlwaysOnTop; - } - void set(bool value) - { - if (m_isAlwaysOnTop != value) - { - m_isAlwaysOnTop = value; - RaisePropertyChanged(L"IsAlwaysOnTop"); - } - } - } + static property Platform::String + ^ IsProgrammerPropertyName { Platform::String ^ get() { return Platform::StringReference(L"IsProgrammer"); } } property bool IsEditingEnabled { @@ -280,65 +249,12 @@ namespace CalculatorApp } } - property int TokenPosition - { - int get() - { - return m_tokenPosition; - } - void set(int value) - { - m_tokenPosition = value; - } - } - - property Platform::String^ SelectedExpressionLastData - { - Platform::String^ get() { return m_selectedExpressionLastData; } - void set(Platform::String^ value) { m_selectedExpressionLastData = value; } - } - - property bool KeyPressed - { - bool get() - { - return m_keyPressed; - } - void set(bool value) - { - m_keyPressed = value; - } - } - - property bool IsOperandUpdatedUsingViewModel - { - bool get() - { - return m_operandUpdated; - } - void set(bool value) - { - m_operandUpdated = value; - } - } - - property bool IsOperandTextCompletelySelected - { - bool get() - { - return m_completeTextSelection; - } - void set(bool value) - { - m_completeTextSelection = value; - } - } - - internal : void OnPaste(Platform::String ^ pastedString); + internal : + void OnPaste(Platform::String ^ pastedString); void OnCopyCommand(Platform::Object ^ parameter); void OnPasteCommand(Platform::Object ^ parameter); - NumbersAndOperatorsEnum MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate); + ButtonInfo MapCharacterToButtonId(char16 ch); // Memory feature related methods. They are internal because they need to called from the MainPage code-behind void OnMemoryButtonPressed(); @@ -348,15 +264,8 @@ namespace CalculatorApp void OnMemoryClear(_In_ Platform::Object ^ memoryItemPosition); void OnPinUnpinCommand(Platform::Object ^ parameter); - void SetPrimaryDisplay(_In_ std::wstring const& displayString, _In_ bool isError); + void OnInputChanged(); void DisplayPasteError(); - void SetTokens(_Inout_ std::shared_ptr>> const& tokens); - void SetExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands); - void SetHistoryExpressionDisplay( - _Inout_ std::shared_ptr>> const& tokens, - _Inout_ std::shared_ptr>> const& commands); void SetParenthesisCount(_In_ unsigned int parenthesisCount); void SetOpenParenthesisCountNarratorAnnouncement(); void OnNoRightParenAdded(); @@ -373,14 +282,11 @@ namespace CalculatorApp void Recalculate(bool fromHistory = false); bool IsOperator(CalculationManager::Command cmdenum); void FtoEButtonToggled(); - void SwitchProgrammerModeBase(RADIX_TYPE calculatorBase); + void SwitchProgrammerModeBase(CalculatorApp::Common::NumberBase calculatorBase); void SetMemorizedNumbersString(); void SwitchAngleType(NumbersAndOperatorsEnum num); void ResetDisplay(); - RADIX_TYPE GetCurrentRadixType() - { - return (RADIX_TYPE)m_CurrentRadixType; - } + void SetPrecision(int32_t precision); void UpdateMaxIntDigits() { @@ -390,12 +296,21 @@ namespace CalculatorApp { return m_CurrentAngleType; } - + void SelectHistoryItem(HistoryItemViewModel ^ item); private: void SetMemorizedNumbers(const std::vector& memorizedNumbers); void UpdateProgrammerPanelDisplay(); void HandleUpdatedOperandData(CalculationManager::Command cmdenum); + void SetPrimaryDisplay(_In_ Platform::String ^ displayStringValue, _In_ bool isError); + void SetExpressionDisplay( + _Inout_ std::shared_ptr>> const& tokens, + _Inout_ std::shared_ptr>> const& commands); + void SetHistoryExpressionDisplay( + _Inout_ std::shared_ptr>> const& tokens, + _Inout_ std::shared_ptr>> const& commands); + void SetTokens(_Inout_ std::shared_ptr>> const& tokens); NumbersAndOperatorsEnum ConvertIntegerToNumbersAndOperatorsEnum(unsigned int parameter); + static RADIX_TYPE GetRadixTypeFromNumberBase(CalculatorApp::Common::NumberBase base); NumbersAndOperatorsEnum m_CurrentAngleType; wchar_t m_decimalSeparator; CalculatorDisplay m_calculatorDisplay; @@ -423,16 +338,11 @@ namespace CalculatorApp bool m_isStandard; bool m_isScientific; bool m_isProgrammer; - bool m_isAlwaysOnTop; - bool m_isBinaryBitFlippingEnabled; bool m_isBitFlipChecked; - bool m_isShiftChecked; bool m_isRtlLanguage; - int m_tokenPosition; - bool m_keyPressed; bool m_operandUpdated; - bool m_completeTextSelection; bool m_isLastOperationHistoryLoad; + CalculatorApp::Common::BitLength m_valueBitLength; Platform::String ^ m_selectedExpressionLastData; Common::DisplayExpressionToken ^ m_selectedExpressionToken; @@ -452,15 +362,15 @@ namespace CalculatorApp std::wstring AddPadding(std::wstring); size_t LengthWithoutPadding(std::wstring); - std::shared_ptr>> m_tokens; - std::shared_ptr>> m_commands; + std::shared_ptr>> m_tokens; + std::shared_ptr>> m_commands; // Token types - bool IsUnaryOp(int nOpCode); - bool IsBinOp(int nOpcode); - bool IsTrigOp(int nOpCode); - bool IsOpnd(int nOpCode); - bool IsRecoverableCommand(int nOpCode); + bool IsUnaryOp(CalculationManager::Command command); + bool IsBinOp(CalculationManager::Command command); + bool IsTrigOp(CalculationManager::Command command); + bool IsOpnd(CalculationManager::Command command); + bool IsRecoverableCommand(CalculationManager::Command command); CalculationManager::CommandType GetSelectedTokenType(_In_ unsigned int); void SaveEditedCommand(_In_ unsigned int index, _In_ CalculationManager::Command command); @@ -473,7 +383,6 @@ namespace CalculatorApp friend class CalculatorDisplay; friend class CalculatorFunctionalTests::HistoryTests; friend class CalculatorUnitTests::MultiWindowUnitTests; - friend class CalculatorUnitTests::TimerTests; }; } } diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp index e57b0dc3..bab3c786 100644 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ b/src/CalcViewModel/UnitConverterViewModel.cpp @@ -137,12 +137,12 @@ UnitConverterViewModel::UnitConverterViewModel(const shared_ptrFractionDigits; auto resourceLoader = AppResourceProvider::GetInstance(); - m_localizedValueFromFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueFromFormat); - m_localizedValueToFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueToFormat); - m_localizedConversionResultFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ConversionResultFormat); - m_localizedValueFromDecimalFormat = resourceLoader.GetResourceString(UnitConverterResourceKeys::ValueFromDecimalFormat); - m_localizedInputUnitName = resourceLoader.GetResourceString(UnitConverterResourceKeys::InputUnit_Name); - m_localizedOutputUnitName = resourceLoader.GetResourceString(UnitConverterResourceKeys::OutputUnit_Name); + m_localizedValueFromFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ValueFromFormat); + m_localizedValueToFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ValueToFormat); + m_localizedConversionResultFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ConversionResultFormat); + m_localizedValueFromDecimalFormat = resourceLoader->GetResourceString(UnitConverterResourceKeys::ValueFromDecimalFormat); + m_localizedInputUnitName = resourceLoader->GetResourceString(UnitConverterResourceKeys::InputUnit_Name); + m_localizedOutputUnitName = resourceLoader->GetResourceString(UnitConverterResourceKeys::OutputUnit_Name); Unit1AutomationName = m_localizedInputUnitName; Unit2AutomationName = m_localizedOutputUnitName; @@ -390,7 +390,7 @@ String ^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& st void UnitConverterViewModel::DisplayPasteError() { - String ^ errorMsg = AppResourceProvider::GetInstance().GetCEngineString(StringReference(SIDS_DOMAIN)); /*SIDS_DOMAIN is for "invalid input"*/ + String ^ errorMsg = AppResourceProvider::GetInstance()->GetCEngineString(StringReference(SIDS_DOMAIN)); /*SIDS_DOMAIN is for "invalid input"*/ Value1 = errorMsg; Value2 = errorMsg; m_relocalizeStringOnSwitch = false; @@ -476,10 +476,10 @@ void UnitConverterViewModel::OnButtonPressed(Platform::Object ^ parameter) return; } - static const vector OPERANDS = { UCM::Command::Zero, UCM::Command::One, UCM::Command::Two, UCM::Command::Three, UCM::Command::Four, + static constexpr UCM::Command OPERANDS[] = { UCM::Command::Zero, UCM::Command::One, UCM::Command::Two, UCM::Command::Three, UCM::Command::Four, UCM::Command::Five, UCM::Command::Six, UCM::Command::Seven, UCM::Command::Eight, UCM::Command::Nine }; - if (find(begin(OPERANDS), end(OPERANDS), command) != OPERANDS.end()) + if (find(begin(OPERANDS), end(OPERANDS), command) != end(OPERANDS)) { if (m_isInputBlocked) { @@ -494,7 +494,7 @@ void UnitConverterViewModel::OnButtonPressed(Platform::Object ^ parameter) m_model->SendCommand(command); - TraceLogger::GetInstance().LogConverterInputReceived(Mode); + TraceLogger::GetInstance()->LogConverterInputReceived(Mode); } void UnitConverterViewModel::OnCopyCommand(Platform::Object ^ parameter) @@ -515,8 +515,10 @@ void UnitConverterViewModel::OnPasteCommand(Platform::Object ^ parameter) // Ensure that the paste happens on the UI thread // EventWriteClipboardPaste_Start(); // Any converter ViewMode is fine here. - CopyPasteManager::GetStringToPaste(m_Mode, NavCategory::GetGroupType(m_Mode)) - .then([this](String ^ pastedString) { OnPaste(pastedString); }, concurrency::task_continuation_context::use_current()); + + auto that(this); + create_task(CopyPasteManager::GetStringToPaste(m_Mode, NavCategory::GetGroupType(m_Mode), NumberBase::Unknown, BitLength::BitLengthUnknown)) + .then([that](String ^ pastedString) { that->OnPaste(pastedString); }, concurrency::task_continuation_context::use_current()); } void UnitConverterViewModel::InitializeView() @@ -650,7 +652,7 @@ void UnitConverterViewModel::OnCurrencyDataLoadFinished(bool didLoad) ResetCategory(); StringReference key = didLoad ? UnitConverterResourceKeys::CurrencyRatesUpdated : UnitConverterResourceKeys::CurrencyRatesUpdateFailed; - String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(key); + String ^ announcement = AppResourceProvider::GetInstance()->GetResourceString(key); Announcement = CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(announcement); } @@ -665,17 +667,18 @@ void UnitConverterViewModel::RefreshCurrencyRatios() m_isCurrencyDataLoaded = false; IsCurrencyLoadingVisible = true; - String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(UnitConverterResourceKeys::UpdatingCurrencyRates); + String ^ announcement = AppResourceProvider::GetInstance()->GetResourceString(UnitConverterResourceKeys::UpdatingCurrencyRates); Announcement = CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(announcement); - auto refreshTask = create_task([this] { return m_model->RefreshCurrencyRatios().get(); }); + auto that(this); + auto refreshTask = create_task([that] { return that->m_model->RefreshCurrencyRatios().get(); }); refreshTask.then( - [this](const pair& refreshResult) { + [that](const pair& refreshResult) { bool didLoad = refreshResult.first; wstring timestamp = refreshResult.second; - OnCurrencyTimestampUpdated(timestamp, false /*isWeekOldData*/); - OnCurrencyDataLoadFinished(didLoad); + that->OnCurrencyTimestampUpdated(timestamp, false /*isWeekOldData*/); + that->OnCurrencyDataLoadFinished(didLoad); }, task_continuation_context::use_current()); } @@ -878,22 +881,22 @@ NumbersAndOperatorsEnum UnitConverterViewModel::MapCharacterToButtonId(const wch void UnitConverterViewModel::OnPaste(String ^ stringToPaste) { // If pastedString is invalid("NoOp") then display pasteError else process the string - if (stringToPaste == StringReference(CopyPasteManager::PasteErrorString)) + if (CopyPasteManager::IsErrorMessage(stringToPaste)) { this->DisplayPasteError(); return; } - TraceLogger::GetInstance().LogInputPasted(Mode); + TraceLogger::GetInstance()->LogInputPasted(Mode); bool isFirstLegalChar = true; bool sendNegate = false; - wstring accumulation = L""; + wstring accumulation; - for (auto it = stringToPaste->Begin(); it != stringToPaste->End(); it++) + for (const auto ch : stringToPaste) { bool canSendNegate = false; - NumbersAndOperatorsEnum op = MapCharacterToButtonId(*it, canSendNegate); + NumbersAndOperatorsEnum op = MapCharacterToButtonId(ch, canSendNegate); if (NumbersAndOperatorsEnum::None != op) { @@ -929,7 +932,7 @@ void UnitConverterViewModel::OnPaste(String ^ stringToPaste) } } - accumulation += *it; + accumulation += ch; UpdateInputBlocked(accumulation); if (m_isInputBlocked) { @@ -954,8 +957,7 @@ String ^ UnitConverterViewModel::GetLocalizedAutomationName(_In_ String ^ displa format = m_localizedValueFromDecimalFormat; } - wstring localizedResult = LocalizationStringUtil::GetLocalizedString(format->Data(), displayvalue->Data(), unitname->Data()); - return ref new String(localizedResult.c_str()); + return LocalizationStringUtil::GetLocalizedString(format, displayvalue, unitname); } String @@ -965,11 +967,7 @@ String _In_ String ^ toValue, _In_ String ^ toUnit) { - String ^ localizedString = - ref new String(LocalizationStringUtil::GetLocalizedString( - m_localizedConversionResultFormat->Data(), fromValue->Data(), fromUnit->Data(), toValue->Data(), toUnit->Data()) - .c_str()); - return localizedString; + return LocalizationStringUtil::GetLocalizedString(m_localizedConversionResultFormat, fromValue, fromUnit, toValue, toUnit); } void UnitConverterViewModel::UpdateValue1AutomationName() @@ -990,9 +988,9 @@ void UnitConverterViewModel::UpdateValue2AutomationName() void UnitConverterViewModel::OnMaxDigitsReached() { - String ^ format = AppResourceProvider::GetInstance().GetResourceString(UnitConverterResourceKeys::MaxDigitsReachedFormat); - const wstring& announcement = LocalizationStringUtil::GetLocalizedString(format->Data(), m_lastAnnouncedConversionResult->Data()); - Announcement = CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(StringReference(announcement.c_str())); + String ^ format = AppResourceProvider::GetInstance()->GetResourceString(UnitConverterResourceKeys::MaxDigitsReachedFormat); + auto announcement = LocalizationStringUtil::GetLocalizedString(format, m_lastAnnouncedConversionResult); + Announcement = CalculatorAnnouncement::GetMaxDigitsReachedAnnouncement(announcement); } bool UnitConverterViewModel::UnitsAreValid() @@ -1002,17 +1000,18 @@ bool UnitConverterViewModel::UnitsAreValid() void UnitConverterViewModel::StartConversionResultTimer() { - m_conversionResultTaskHelper = make_unique(CONVERSION_FINALIZED_DELAY_IN_MS, [this]() { - if (UnitsAreValid()) + auto that(this); + m_conversionResultTaskHelper = make_unique(CONVERSION_FINALIZED_DELAY_IN_MS, [that]() { + if (that->UnitsAreValid()) { - String ^ valueFrom = m_Value1Active ? m_Value1 : m_Value2; - String ^ valueTo = m_Value1Active ? m_Value2 : m_Value1; + String ^ valueFrom = that->m_Value1Active ? that->m_Value1 : that->m_Value2; + String ^ valueTo = that->m_Value1Active ? that->m_Value2 : that->m_Value1; } }); } String ^ SupplementaryResult::GetLocalizedAutomationName() { - auto format = AppResourceProvider::GetInstance().GetResourceString("SupplementaryUnit_AutomationName"); - return ref new String(LocalizationStringUtil::GetLocalizedString(format->Data(), this->Value->Data(), this->Unit->Name->Data()).c_str()); + auto format = AppResourceProvider::GetInstance()->GetResourceString("SupplementaryUnit_AutomationName"); + return LocalizationStringUtil::GetLocalizedString(format, this->Value, this->Unit->Name); } diff --git a/src/CalcViewModel/ViewState.cpp b/src/CalcViewModel/ViewState.cpp deleted file mode 100644 index 63a5d30e..00000000 --- a/src/CalcViewModel/ViewState.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "ViewState.h" - -namespace CalculatorApp -{ - namespace ViewState - { - Platform::StringReference Snap(L"Snap"); - Platform::StringReference DockedView(L"DockedView"); - - bool IsValidViewState(Platform::String ^ viewState) - { - return viewState->Equals(ViewState::Snap) || viewState->Equals(ViewState::DockedView); - } - } -} diff --git a/src/CalcViewModel/ViewState.h b/src/CalcViewModel/ViewState.h deleted file mode 100644 index 0a103d09..00000000 --- a/src/CalcViewModel/ViewState.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace ViewState - { - extern Platform::StringReference Snap; - extern Platform::StringReference DockedView; - - bool IsValidViewState(Platform::String ^ viewState); - } -} diff --git a/src/CalcViewModel/packages.config b/src/CalcViewModel/packages.config index cef4e13e..c148e5d7 100644 --- a/src/CalcViewModel/packages.config +++ b/src/CalcViewModel/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/CalcViewModel/pch.h b/src/CalcViewModel/pch.h index 575a1f0d..77e1094b 100644 --- a/src/CalcViewModel/pch.h +++ b/src/CalcViewModel/pch.h @@ -31,6 +31,8 @@ #include #include #include +#include + // C++\WinRT Headers #include "winrt/base.h" #include "winrt/Windows.Foundation.Diagnostics.h" diff --git a/src/Calculator/AboutFlyout.xaml.cpp b/src/Calculator/AboutFlyout.xaml.cpp index 87a15e69..5f295c59 100644 --- a/src/Calculator/AboutFlyout.xaml.cpp +++ b/src/Calculator/AboutFlyout.xaml.cpp @@ -21,7 +21,7 @@ using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Data; #ifndef BUILD_YEAR -#define BUILD_YEAR 2019 +#define BUILD_YEAR 2020 #endif AboutFlyout::AboutFlyout() @@ -35,11 +35,11 @@ AboutFlyout::AboutFlyout() 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()); + LocalizationStringUtil::GetLocalizedString(resourceLoader->GetResourceString("AboutControlCopyright"), StringReference(to_wstring(BUILD_YEAR).c_str())); + AboutControlCopyrightRun->Text = copyrightText; } void AboutFlyout::FeedbackButton_Click(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e) @@ -53,7 +53,7 @@ void AboutFlyout::FeedbackButton_Click(_In_ Object ^ sender, _In_ RoutedEventArg void AboutFlyout::SetVersionString() { PackageVersion version = Package::Current->Id->Version; - String ^ appName = AppResourceProvider::GetInstance().GetResourceString(L"AppName"); + String ^ appName = AppResourceProvider::GetInstance()->GetResourceString(L"AppName"); AboutFlyoutVersion->Text = appName + L" " + version.Major + L"." + version.Minor + L"." + version.Build + L"." + version.Revision; } diff --git a/src/Calculator/App.xaml b/src/Calculator/App.xaml index d9b2d7ba..f27dcdf8 100644 --- a/src/Calculator/App.xaml +++ b/src/Calculator/App.xaml @@ -17,17 +17,33 @@ 0 #FF000000 #FF2B2B2B + #FF858585 + - - + + + + + + + + + 0,0,0,0 0 #FFF2F2F2 #FFE0E0E0 + #FF858585 + - - + + + + + + + + + 0,1,0,0 @@ -91,17 +129,23 @@ + - + + + + + + @@ -116,6 +160,21 @@ 15 SemiBold + 64 + 24 + 24 + 16 + + 64 + 16 + 20 + 10 + + 38 + 12 + 16 + 8 + 12 15 24 @@ -125,13 +184,17 @@ 40 34 + 38 + 48 24 20 + 22 15 12 - 15 + 14 + 16 + + + + + - + + + + @@ -457,6 +562,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +