mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-23 06:25:19 -07:00
Merge branch 'master' into Fix605
This commit is contained in:
commit
8505aa99aa
509 changed files with 80655 additions and 21725 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -291,6 +291,9 @@ __pycache__/
|
||||||
Generated Files/
|
Generated Files/
|
||||||
src/GraphControl/GraphingImplOverrides.props
|
src/GraphControl/GraphingImplOverrides.props
|
||||||
src/CalcViewModel/DataLoaders/DataLoaderConstants.h
|
src/CalcViewModel/DataLoaders/DataLoaderConstants.h
|
||||||
!/build/config/TRexDefs/**
|
!src/Calculator/WindowsDev_TemporaryKey.pfx
|
||||||
!src/Calculator/TemporaryKey.pfx
|
!src/CalculatorUnitTests/WindowsDev_TemporaryKey.pfx
|
||||||
!src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx
|
!src/x64
|
||||||
|
!src/x86
|
||||||
|
!src/out
|
||||||
|
!src/ARM
|
|
@ -51,6 +51,10 @@ We also welcome [issues submitted on GitHub](https://github.com/Microsoft/calcul
|
||||||
## Roadmap
|
## Roadmap
|
||||||
For information regarding Windows Calculator plans and release schedule, please see the [Windows Calculator Roadmap](docs/Roadmap.md).
|
For information regarding Windows Calculator plans and release schedule, please see the [Windows Calculator Roadmap](docs/Roadmap.md).
|
||||||
|
|
||||||
|
### Graphing Mode
|
||||||
|
Adding graphing calculator functionality [is on the project roadmap](https://github.com/Microsoft/calculator/issues/338) and we hope that this project can create a great end-user experience around graphing. To that end, the UI from the official in-box Windows Calculator is currently part of this repository, although the proprietary Microsoft-built graphing engine, which also drives graphing in Microsoft Mathematics and OneNote, is not. Community members can still be involved in the creation of the UI, however developer builds will not have graphing functionality due to the use of a [mock implementation of the engine](/src/GraphingImpl/Mocks) built on top of a
|
||||||
|
[common graphing API](/src/GraphingInterfaces).
|
||||||
|
|
||||||
## Diagnostic Data
|
## Diagnostic Data
|
||||||
This project collects usage data and sends it to Microsoft to help improve our products and services.
|
This project collects usage data and sends it to Microsoft to help improve our products and services.
|
||||||
Read our [privacy statement](https://go.microsoft.com/fwlink/?LinkId=521839) to learn more.
|
Read our [privacy statement](https://go.microsoft.com/fwlink/?LinkId=521839) to learn more.
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Modules>
|
|
||||||
<Module
|
|
||||||
name="Microsoft.Windows.Apps.Calculator"
|
|
||||||
tdbuildteamid="86">
|
|
||||||
<File
|
|
||||||
location="Calculator"
|
|
||||||
path="%TFS_SOURCESDIRECTORY%\src\Calculator\Resources\en-US\Resources.resw" />
|
|
||||||
<File
|
|
||||||
location="Calculator"
|
|
||||||
path="%TFS_SOURCESDIRECTORY%\src\Calculator\Resources\en-US\CEngineStrings.resw" />
|
|
||||||
</Module>
|
|
||||||
</Modules>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<SignConfigXML>
|
|
||||||
<job platform="" configuration="" certSubject="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" jobname="EngFunSimpleSign" approvers="">
|
|
||||||
<file src="__INPATHROOT__\Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle" signType="136020001" dest="__OUTPATHROOT__\Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle" />
|
|
||||||
</job>
|
|
||||||
</SignConfigXML>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE AMD64 Desktop WinPerf Test Run</BuildLogName>
|
|
||||||
<TemplateId>134858</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Performance_AMD64.testlist</RelativeFilePath>
|
|
||||||
<!-- Needed to be able to process multiple results for the same test case but not have reliability run checked on the task -->
|
|
||||||
<OptionalMetadataItems>
|
|
||||||
<OptionalMetadataItem>
|
|
||||||
<Key>VSTS\IsReliabilityRun</Key>
|
|
||||||
<Value>True</Value>
|
|
||||||
</OptionalMetadataItem>
|
|
||||||
</OptionalMetadataItems>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS4_RELEASE AMD64 DesktopVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>139642</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_AMD64.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs4_release</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<!-- RS5_RELEASE Desktop x64 VM run -->
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS5_RELEASE AMD64 DesktopVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>139642</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_AMD64.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs5_release</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,44 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE AMD64 DesktopVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>139642</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_AMD64.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs_apps_validate</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE AMD64 WCOS Test Run</BuildLogName>
|
|
||||||
<TemplateId>153648</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>WCOS_AMD64.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs_apps_validate</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,31 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<!--RS_PRERELEASE ARM WinCoreOS WinPerf run. -->
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_PRERELEASE ARM WindowsCore WinPerf Test Run</BuildLogName>
|
|
||||||
<TemplateId>135258</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Performance_ARM.testlist</RelativeFilePath>
|
|
||||||
<!-- Needed to be able to process multiple results for the same test case but not have reliability run checked on the task -->
|
|
||||||
<OptionalMetadataItems>
|
|
||||||
<OptionalMetadataItem>
|
|
||||||
<Key>VSTS\IsReliabilityRun</Key>
|
|
||||||
<Value>True</Value>
|
|
||||||
</OptionalMetadataItem>
|
|
||||||
</OptionalMetadataItems>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<!-- RS_APPS_VALIDATE WindowsCore ARM Device run -->
|
|
||||||
<!-- Disabling this until we have a testlist template -->
|
|
||||||
<!--<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE ARM WCOS Test Run</BuildLogName>
|
|
||||||
<TemplateId>140487</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_ARM.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs_apps_validate</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>-->
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<!-- RS_APPS_VALIDATE Desktop x86 VM run -->
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE x86 DesktopVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>139643</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_x86.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs4_release</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<!-- RS_PRERELEASE Desktop x86 VM run -->
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE x86 DesktopVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>139643</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_x86.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs5_release</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,46 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<TReXRunConfigurations>
|
|
||||||
|
|
||||||
<!-- RS_APPS_VALIDATE Desktop x86 VM run -->
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_APPS_VALIDATE x86 DesktopVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>139643</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>Desktop_x86.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs_apps_validate</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
<!-- RS_APPS_VALIDATE WindowsCore x86 VM run -->
|
|
||||||
<TReXRunConfiguration>
|
|
||||||
<BuildLogName>RS_PRERELEASE x86 WindowsCoreVM Test Run</BuildLogName>
|
|
||||||
<TemplateId>153715</TemplateId>
|
|
||||||
<Owner>paxeedev</Owner>
|
|
||||||
<PrivateRun>true</PrivateRun>
|
|
||||||
<CopyFirstJobSettingWithJobOverride>true</CopyFirstJobSettingWithJobOverride>
|
|
||||||
<RelativeFilePath>WCOS_x86.testlist</RelativeFilePath>
|
|
||||||
<Branch>rs_apps_validate</Branch>
|
|
||||||
<WorkflowParameters>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
<WorkflowParameter>
|
|
||||||
<Key>_AlternatePackageRoot</Key>
|
|
||||||
<Value>\\pkges\release\TAEF\validation.taef.provenance\1812.20007-develop\UniversalTestPackages;\\edge-svcs\Release\MITALite\Apps_eng.mitalite_ci\Latest.tst</Value>
|
|
||||||
</WorkflowParameter>
|
|
||||||
</WorkflowParameters>
|
|
||||||
</TReXRunConfiguration>
|
|
||||||
|
|
||||||
</TReXRunConfigurations>
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://universaltest/schema/testlist-2.json",
|
|
||||||
"TestMDs": [
|
|
||||||
{
|
|
||||||
"FilePath": "Calculator.UITests\\Prebuilt\\Test\\arm\\fre\\Calculator.UITests.testmd",
|
|
||||||
"ExecutionProfile": "All"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FilePath": "CalculatorUnitTests\\Prebuilt\\Test\\arm\\fre\\CalculatorUnitTests.testmd",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://universaltest/schema/testlist-2.json",
|
|
||||||
"TestMDs": [
|
|
||||||
{
|
|
||||||
"FilePath": "Calculator.UITests\\Prebuilt\\Test\\arm\\fre\\Calculator.UITests.testmd",
|
|
||||||
"ExecutionProfile": "Performance"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://universaltest/schema/testlist-2.json",
|
|
||||||
"TestMDs": [
|
|
||||||
{
|
|
||||||
"FilePath": "Calculator.UITests\\Prebuilt\\Test\\arm\\fre\\Calculator.UITests.testmd",
|
|
||||||
"ExecutionProfile": "All"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FilePath": "CalculatorUnitTests\\Prebuilt\\Test\\arm\\fre\\CalculatorUnitTests.testmd",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://universaltest/schema/testlist-2.json",
|
|
||||||
"TestMDs": [
|
|
||||||
{
|
|
||||||
"FilePath": "Calculator.UITests\\Prebuilt\\Test\\arm64\\fre\\Calculator.UITests.testmd",
|
|
||||||
"ExecutionProfile": "All"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FilePath": "CalculatorUnitTests\\Prebuilt\\Test\\arm64\\fre\\CalculatorUnitTests.testmd",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://universaltest/schema/testlist-2.json",
|
|
||||||
"TestMDs": [
|
|
||||||
{
|
|
||||||
"FilePath": "Calculator.UITests\\Prebuilt\\Test\\arm64\\fre\\Calculator.UITests.testmd",
|
|
||||||
"ExecutionProfile": "All"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"FilePath": "CalculatorUnitTests\\Prebuilt\\Test\\arm64\\fre\\CalculatorUnitTests.testmd",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
{
|
|
||||||
"Branch": [
|
|
||||||
{
|
|
||||||
"collection":"microsoft",
|
|
||||||
"project":"OS",
|
|
||||||
"repo":"os",
|
|
||||||
"name":"official/rs_apps_utils",
|
|
||||||
"CheckinFiles": [
|
|
||||||
{
|
|
||||||
"source":"vpack/app/calculator.app.man",
|
|
||||||
"path": "/redist/mspartners/ipa/Calculator",
|
|
||||||
"type": "File"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source":"vpack/app/calculator.app.man",
|
|
||||||
"path": "/onecoreuap/redist/mspartners/ipa/Calculator",
|
|
||||||
"type": "File"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Email": [
|
|
||||||
{
|
|
||||||
"sendTo":"paxeedev",
|
|
||||||
"sendOnErrorOnly": "True"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
{
|
|
||||||
"Branch": [
|
|
||||||
{
|
|
||||||
"collection":"microsoft",
|
|
||||||
"project":"OS",
|
|
||||||
"repo":"os",
|
|
||||||
"name":"official/rs_apps_validate",
|
|
||||||
"CheckinFiles": [
|
|
||||||
{
|
|
||||||
"source":"vpack/app/calculator.app.man",
|
|
||||||
"path": "/redist/mspartners/ipa/Calculator",
|
|
||||||
"type": "File"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source":"vpack/app/calculator.app.man",
|
|
||||||
"path": "/onecoreuap/redist/mspartners/ipa/Calculator",
|
|
||||||
"type": "File"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Email": [
|
|
||||||
{
|
|
||||||
"sendTo":"paxeedev",
|
|
||||||
"sendOnErrorOnly": "True"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -6,11 +6,11 @@
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
- master
|
- master
|
||||||
- servicing/*
|
- release/*
|
||||||
- feature/*
|
- feature/*
|
||||||
pr:
|
pr:
|
||||||
- master
|
- master
|
||||||
- servicing/*
|
- release/*
|
||||||
- feature/*
|
- feature/*
|
||||||
|
|
||||||
name: 0.$(Date:yyMM).$(DayOfMonth)$(Rev:rr).0
|
name: 0.$(Date:yyMM).$(DayOfMonth)$(Rev:rr).0
|
||||||
|
@ -23,6 +23,7 @@ jobs:
|
||||||
- template: ./templates/build-app-public.yaml
|
- template: ./templates/build-app-public.yaml
|
||||||
parameters:
|
parameters:
|
||||||
platform: x86
|
platform: x86
|
||||||
|
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
|
||||||
|
|
||||||
- template: ./templates/build-app-public.yaml
|
- template: ./templates/build-app-public.yaml
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
@ -4,13 +4,20 @@
|
||||||
# Store and the Windows image. This pipeline relies on Microsoft-internal resources to run.
|
# Store and the Windows image. This pipeline relies on Microsoft-internal resources to run.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
schedules:
|
||||||
|
- cron: "0 7 * * *"
|
||||||
|
displayName: Daily midnight build
|
||||||
|
branches:
|
||||||
|
include:
|
||||||
|
- master
|
||||||
|
|
||||||
trigger: none
|
trigger: none
|
||||||
pr: none
|
pr: none
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
versionMajor: 10
|
versionMajor: 10
|
||||||
versionMinor: 1910
|
versionMinor: 2012
|
||||||
versionBuild: $[counter('10.1910.*', 0)]
|
versionBuild: $[counter('10.2012.*', 0)]
|
||||||
versionPatch: 0
|
versionPatch: 0
|
||||||
|
|
||||||
name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)'
|
name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)'
|
||||||
|
@ -30,11 +37,6 @@ jobs:
|
||||||
platform: ARM
|
platform: ARM
|
||||||
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
|
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
|
||||||
|
|
||||||
- template: ./templates/build-app-internal.yaml
|
|
||||||
parameters:
|
|
||||||
platform: ARM64
|
|
||||||
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
|
|
||||||
|
|
||||||
- template: ./templates/run-ui-tests.yaml
|
- template: ./templates/run-ui-tests.yaml
|
||||||
parameters:
|
parameters:
|
||||||
platform: x64
|
platform: x64
|
||||||
|
@ -54,5 +56,7 @@ jobs:
|
||||||
platform: x86
|
platform: x86
|
||||||
|
|
||||||
- template: ./templates/package-appxbundle.yaml
|
- template: ./templates/package-appxbundle.yaml
|
||||||
|
parameters:
|
||||||
|
signBundle: true
|
||||||
|
|
||||||
- template: ./templates/prepare-release-internalonly.yaml
|
- template: ./templates/prepare-release-internalonly.yaml
|
||||||
|
|
|
@ -16,20 +16,18 @@ jobs:
|
||||||
variables:
|
variables:
|
||||||
BuildConfiguration: Release
|
BuildConfiguration: Release
|
||||||
BuildPlatform: ${{ parameters.platform }}
|
BuildPlatform: ${{ parameters.platform }}
|
||||||
workspace:
|
|
||||||
clean: outputs
|
|
||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
clean: true
|
fetchDepth: 1
|
||||||
|
|
||||||
- task: UniversalPackages@0
|
- task: UniversalPackages@0
|
||||||
displayName: Download internals package
|
displayName: Download internals package
|
||||||
inputs:
|
inputs:
|
||||||
command: download
|
command: download
|
||||||
downloadDirectory: $(Build.SourcesDirectory)
|
downloadDirectory: $(Build.SourcesDirectory)
|
||||||
vstsFeed: WindowsApps
|
vstsFeed: WindowsInboxApps
|
||||||
vstsFeedPackage: calculator-internals
|
vstsFeedPackage: calculator-internals
|
||||||
vstsPackageVersion: 0.0.31
|
vstsPackageVersion: 0.0.53
|
||||||
|
|
||||||
- template: ./build-single-architecture.yaml
|
- template: ./build-single-architecture.yaml
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
@ -14,10 +14,8 @@ jobs:
|
||||||
variables:
|
variables:
|
||||||
BuildConfiguration: Release
|
BuildConfiguration: Release
|
||||||
BuildPlatform: ${{ parameters.platform }}
|
BuildPlatform: ${{ parameters.platform }}
|
||||||
workspace:
|
|
||||||
clean: outputs
|
|
||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
clean: true
|
fetchDepth: 1
|
||||||
|
|
||||||
- template: ./build-single-architecture.yaml
|
- template: ./build-single-architecture.yaml
|
|
@ -5,11 +5,10 @@ parameters:
|
||||||
extraMsBuildArgs: ''
|
extraMsBuildArgs: ''
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- task: NuGetToolInstaller@0
|
- task: NuGetToolInstaller@1
|
||||||
displayName: Use NuGet 5.0.2
|
displayName: Use NuGet 5.x
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: 5.0.2
|
versionSpec: 5.x
|
||||||
checkLatest: true
|
|
||||||
|
|
||||||
# In most accounts, you can just use 'NuGetCommand' instead of this GUID.
|
# In most accounts, you can just use 'NuGetCommand' instead of this GUID.
|
||||||
# In the microsoft.visualstudio.com account, NuGetCommand is ambiguous so the GUID is needed.
|
# In the microsoft.visualstudio.com account, NuGetCommand is ambiguous so the GUID is needed.
|
||||||
|
@ -17,7 +16,7 @@ steps:
|
||||||
displayName: NuGet restore src/Calculator.sln
|
displayName: NuGet restore src/Calculator.sln
|
||||||
inputs:
|
inputs:
|
||||||
command: custom
|
command: custom
|
||||||
arguments: restore src/Calculator.sln -Verbosity Detailed -NonInteractive
|
arguments: restore src/Calculator.sln -Verbosity Detailed
|
||||||
|
|
||||||
- task: PowerShell@2
|
- task: PowerShell@2
|
||||||
displayName: Set version number in AppxManifest
|
displayName: Set version number in AppxManifest
|
||||||
|
@ -33,7 +32,6 @@ steps:
|
||||||
msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ ${{ parameters.extraMsBuildArgs }}
|
msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ ${{ parameters.extraMsBuildArgs }}
|
||||||
platform: $(BuildPlatform)
|
platform: $(BuildPlatform)
|
||||||
configuration: $(BuildConfiguration)
|
configuration: $(BuildConfiguration)
|
||||||
clean: true
|
|
||||||
maximumCpuCount: true
|
maximumCpuCount: true
|
||||||
|
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
|
|
|
@ -1,30 +1,29 @@
|
||||||
# This template contains a job which takes .appx packages which were built separately for each
|
# This template contains a job which takes .appx packages which were built separately for each
|
||||||
# architecture (arm, x86, etc.) and combines them into a single .appxbundle.
|
# architecture (arm, x86, etc.) and combines them into a single .appxbundle.
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
signBundle: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: Package
|
- job: Package
|
||||||
dependsOn:
|
dependsOn:
|
||||||
- Buildx64
|
- Buildx64
|
||||||
- Buildx86
|
- Buildx86
|
||||||
- BuildARM
|
- BuildARM
|
||||||
- BuildARM64
|
|
||||||
condition: |
|
condition: |
|
||||||
and
|
and
|
||||||
(
|
(
|
||||||
in(dependencies.Buildx64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
in(dependencies.Buildx64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
||||||
in(dependencies.Buildx86.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
in(dependencies.Buildx86.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
||||||
in(dependencies.BuildARM.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
|
in(dependencies.BuildARM.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
|
||||||
in(dependencies.BuildARM64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
|
|
||||||
)
|
)
|
||||||
pool:
|
pool:
|
||||||
vmImage: windows-2019
|
vmImage: windows-2019
|
||||||
workspace:
|
|
||||||
clean: outputs
|
|
||||||
variables:
|
variables:
|
||||||
skipComponentGovernanceDetection: true
|
skipComponentGovernanceDetection: true
|
||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
clean: true
|
fetchDepth: 1
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: DownloadBuildArtifacts@0
|
||||||
displayName: Download all .appx artifacts
|
displayName: Download all .appx artifacts
|
||||||
|
@ -60,3 +59,43 @@ jobs:
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: appxBundle
|
artifactName: appxBundle
|
||||||
pathToPublish: $(Build.ArtifactStagingDirectory)\appxBundle
|
pathToPublish: $(Build.ArtifactStagingDirectory)\appxBundle
|
||||||
|
|
||||||
|
- ${{ if eq(parameters.signBundle, true) }}:
|
||||||
|
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||||
|
displayName: Send appxbundle to code signing service
|
||||||
|
inputs:
|
||||||
|
ConnectedServiceName: Essential Experiences Codesign
|
||||||
|
FolderPath: $(Build.ArtifactStagingDirectory)\appxBundle
|
||||||
|
Pattern: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
|
||||||
|
signConfigType: inlineSignParams
|
||||||
|
inlineOperation: |
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"CertTemplateName": "WINMSAPP1ST",
|
||||||
|
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
|
||||||
|
"KeyCode": "Dynamic",
|
||||||
|
"OperationCode": "SigntoolvNextSign",
|
||||||
|
"Parameters": {
|
||||||
|
"OpusName": "Microsoft",
|
||||||
|
"OpusInfo": "http://www.microsoft.com",
|
||||||
|
"FileDigest": "/fd \"SHA256\"",
|
||||||
|
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
|
||||||
|
},
|
||||||
|
"ToolName": "sign",
|
||||||
|
"ToolVersion": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CertTemplateName": "WINMSAPP1ST",
|
||||||
|
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
|
||||||
|
"KeyCode": "Dynamic",
|
||||||
|
"OperationCode": "SigntoolvNextVerify",
|
||||||
|
"Parameters": {},
|
||||||
|
"ToolName": "sign",
|
||||||
|
"ToolVersion": "1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
displayName: Publish AppxBundleSigned artifact
|
||||||
|
inputs:
|
||||||
|
pathtoPublish: $(Build.ArtifactStagingDirectory)\appxBundle
|
||||||
|
artifactName: appxBundleSigned
|
|
@ -2,8 +2,6 @@
|
||||||
# Windows using Microsoft-internal systems. It relies on Microsoft-internal resources and will not
|
# Windows using Microsoft-internal systems. It relies on Microsoft-internal resources and will not
|
||||||
# work outside of Microsoft.
|
# work outside of Microsoft.
|
||||||
# Specifically, this job:
|
# Specifically, this job:
|
||||||
# - Signs the bundle using a secure system. If you want to build your own, use SignTool following
|
|
||||||
# the example in the continuous integration pipeline.
|
|
||||||
# - Builds VPacks for including the app in the Windows OS build. Azure DevOps Universal Packages
|
# - Builds VPacks for including the app in the Windows OS build. Azure DevOps Universal Packages
|
||||||
# offers similar capabilities.
|
# offers similar capabilities.
|
||||||
# - Creates StoreBroker packages containing Microsoft Store assets. Although the Store assets for
|
# - Creates StoreBroker packages containing Microsoft Store assets. Although the Store assets for
|
||||||
|
@ -14,7 +12,7 @@ jobs:
|
||||||
- job: WindowsInternalRelease
|
- job: WindowsInternalRelease
|
||||||
dependsOn: Package
|
dependsOn: Package
|
||||||
pool:
|
pool:
|
||||||
name: Package ES Lab E
|
name: Package ES Standard Build
|
||||||
workspace:
|
workspace:
|
||||||
clean: outputs
|
clean: outputs
|
||||||
variables:
|
variables:
|
||||||
|
@ -39,36 +37,21 @@ jobs:
|
||||||
env:
|
env:
|
||||||
XES_DISABLEPROV: true
|
XES_DISABLEPROV: true
|
||||||
|
|
||||||
- task: NuGetToolInstaller@0
|
- task: NuGetToolInstaller@1
|
||||||
displayName: Use NuGet 4.7.1
|
displayName: Use NuGet 5.x
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: 4.7.1
|
versionSpec: 5.x
|
||||||
checkLatest: true
|
|
||||||
|
|
||||||
- task: DownloadBuildArtifacts@0
|
- task: DownloadBuildArtifacts@0
|
||||||
displayName: Download appxBundle artifact
|
displayName: Download appxBundleSigned artifact
|
||||||
inputs:
|
inputs:
|
||||||
artifactName: appxBundle
|
artifactName: appxBundleSigned
|
||||||
|
|
||||||
- task: PkgESCodeSign@10
|
|
||||||
displayName: Send bundle to Package ES code signing service
|
|
||||||
env:
|
|
||||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
|
||||||
inputs:
|
|
||||||
signConfigXml: build\config\SignConfig.xml
|
|
||||||
inPathRoot: $(Build.ArtifactStagingDirectory)\appxBundle
|
|
||||||
outPathRoot: $(Build.ArtifactStagingDirectory)\appxBundleSigned
|
|
||||||
|
|
||||||
- task: PublishBuildArtifacts@1
|
|
||||||
displayName: Publish AppxBundleSigned artifact
|
|
||||||
inputs:
|
|
||||||
pathtoPublish: $(Build.ArtifactStagingDirectory)\appxBundleSigned
|
|
||||||
artifactName: AppxBundleSigned
|
|
||||||
|
|
||||||
- task: CopyFiles@2
|
- task: CopyFiles@2
|
||||||
displayName: Copy signed AppxBundle to vpack staging folder
|
displayName: Copy signed AppxBundle to vpack staging folder
|
||||||
inputs:
|
inputs:
|
||||||
sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
|
sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
|
||||||
|
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
|
||||||
targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
|
targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
|
||||||
|
|
||||||
- task: PkgESVPack@10
|
- task: PkgESVPack@10
|
||||||
|
@ -81,6 +64,8 @@ jobs:
|
||||||
pushPkgName: calculator.app
|
pushPkgName: calculator.app
|
||||||
version: $(versionMajor).$(versionMinor).$(versionBuild)
|
version: $(versionMajor).$(versionMinor).$(versionBuild)
|
||||||
owner: paxeeapps
|
owner: paxeeapps
|
||||||
|
provData: false
|
||||||
|
|
||||||
|
|
||||||
- task: PublishBuildArtifacts@1
|
- task: PublishBuildArtifacts@1
|
||||||
displayName: Publish vpack\app artifact with vpack manifest
|
displayName: Publish vpack\app artifact with vpack manifest
|
||||||
|
@ -88,16 +73,14 @@ jobs:
|
||||||
pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
|
pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
|
||||||
artifactName: vpack\app
|
artifactName: vpack\app
|
||||||
|
|
||||||
# TODO (macool): create and push internal test packages and test config
|
|
||||||
|
|
||||||
- task: UniversalPackages@0
|
- task: UniversalPackages@0
|
||||||
displayName: Download internals package
|
displayName: Download internals package
|
||||||
inputs:
|
inputs:
|
||||||
command: download
|
command: download
|
||||||
downloadDirectory: $(Build.SourcesDirectory)
|
downloadDirectory: $(Build.SourcesDirectory)
|
||||||
vstsFeed: WindowsApps
|
vstsFeed: WindowsInboxApps
|
||||||
vstsFeedPackage: calculator-internals
|
vstsFeedPackage: calculator-internals
|
||||||
vstsPackageVersion: 0.0.22
|
vstsPackageVersion: 0.0.53
|
||||||
|
|
||||||
- powershell: |
|
- powershell: |
|
||||||
# Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone.
|
# Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone.
|
||||||
|
@ -151,6 +134,8 @@ jobs:
|
||||||
skipPolling: true
|
skipPolling: true
|
||||||
targetPublishMode: Immediate
|
targetPublishMode: Immediate
|
||||||
logPath: '$(SBLogPath)'
|
logPath: '$(SBLogPath)'
|
||||||
|
deletePackages: true
|
||||||
|
numberOfPackagesToKeep: 0
|
||||||
|
|
||||||
- task: PkgESStoreBrokerAeroUpload@10
|
- task: PkgESStoreBrokerAeroUpload@10
|
||||||
displayName: Upload to Aero flighting dashboard
|
displayName: Upload to Aero flighting dashboard
|
||||||
|
|
|
@ -48,3 +48,5 @@ jobs:
|
||||||
runSettingsFile: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/${{ parameters.runsettingsFileName }}
|
runSettingsFile: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/${{ parameters.runsettingsFileName }}
|
||||||
platform: ${{ parameters.platform }}
|
platform: ${{ parameters.platform }}
|
||||||
configuration: Release
|
configuration: Release
|
||||||
|
${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
|
||||||
|
testFiltercriteria: Priority=0
|
||||||
|
|
|
@ -260,17 +260,19 @@ Steps:
|
||||||
4. While in the Menu: Check the About Page
|
4. While in the Menu: Check the About Page
|
||||||
*Expected: Everything in the about page fits into its window*
|
*Expected: Everything in the about page fits into its window*
|
||||||
5. For Scientific Mode: At a Larger Scale
|
5. For Scientific Mode: At a Larger Scale
|
||||||
*Expected: All buttons are present and the up arrow is grayed out.*
|
*Expected: All buttons are present and the 2nd button is grayed out.*
|
||||||
6. For Scientific Mode: At a Smaller Scale
|
6. For Scientific Mode: At a Smaller Scale
|
||||||
*Expected: All buttons are present and the up arrow is able to be toggled.*
|
*Expected: All buttons are present and the 2nd button is able to be toggled.*
|
||||||
7. For Programmer Mode: At a Any Scale
|
7. For Programmer Mode: At a Any Scale
|
||||||
*Expected: All buttons are present and the up arrow is able to be toggled.*
|
*Expected: All buttons are present and the 2nd button is able to be toggled.*
|
||||||
8. For Converter Mode: While Scaling
|
8. For Converter Mode: While Scaling
|
||||||
*Expected: The number pad and input areas move around each other gracefully.*
|
*Expected: The number pad and input areas move around each other gracefully.*
|
||||||
9. Changing Language: Open Settings app > Time & language > Region & language > Add a language > Select a Right to Left (RTL) language such as Hebrew > Install the associated files> Set it to the system default.
|
9. For Graphing Mode: While Scaling
|
||||||
10. Set the system number format preference: Open a Run dialog (WIN + R) > type ‘intl.cpl’ > Enter > In the format dropdown list > Select Hebrew > Apply.
|
*Expected: The number pad, graph area, and input areas move around each other gracefully.*
|
||||||
11. Initiating the change: Package has completed installing > Sign out > Sign in. (This change to the app may also require a reinstallation of the build)
|
10. Changing Language: Open Settings app > Time & language > Region & language > Add a language > Select a Right to Left (RTL) language such as Hebrew > Install the associated files> Set it to the system default.
|
||||||
12. Repeat Steps 2-6 again in a (RTL) language.
|
11. Set the system number format preference: Open a Run dialog (WIN + R) > type ‘intl.cpl’ > Enter > In the format dropdown list > Select Hebrew > Apply.
|
||||||
|
12. Initiating the change: Package has completed installing > Sign out > Sign in. (This change to the app may also require a reinstallation of the build)
|
||||||
|
13. Repeat Steps 2-6 again in a (RTL) language.
|
||||||
*Expected: No elements fall out of intended boundaries.*
|
*Expected: No elements fall out of intended boundaries.*
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,11 +304,60 @@ Verify the following:
|
||||||
11. "Bin" Binary:
|
11. "Bin" Binary:
|
||||||
*Expected: A B C D E F 2 3 4 5 6 7 8 9 are inactive. A maximum of 64 characters can be entered.*
|
*Expected: A B C D E F 2 3 4 5 6 7 8 9 are inactive. A maximum of 64 characters can be entered.*
|
||||||
|
|
||||||
|
**Graphing Mode Test: Verify Graphing mode functions**
|
||||||
|
Steps:
|
||||||
|
1. Launch the "Calculator" app
|
||||||
|
2. Navigate to "Graphing" Calculator
|
||||||
|
3. Enter a function of x in the input field <br>
|
||||||
|
*Expected: Function is plotted in the graph area. Line color matches the colored square next to the input field*
|
||||||
|
4. Select the "+" button below the function input and enter more functions in the fields that appear <br>
|
||||||
|
*Expected: All functions are plotted in the graph area and match the colors of the input field squares*
|
||||||
|
5. Select the colored square for any function <br>
|
||||||
|
*Expected: Visibility of the function in the graph is toggled off/on*
|
||||||
|
6. Select the "Zoom In", "Zoom Out", and "Reset View' buttons in the graph area <br>
|
||||||
|
*Expected: Both X and Y axes zoom in, out, and revert to default settings, respectively*
|
||||||
|
7. Select the Trace button, then click + drag the graph until the red square is near a graphed function<br>
|
||||||
|
*Expected: Closest (X, Y) coordinates of the function to the red square are displayed with a black dot to indicate the location*
|
||||||
|
8. Enter "y=mx+b" into a function input field, then select "Variables" button <br>
|
||||||
|
*Expected: y=x+1 function is plotted in the graph, "Variables" modal window shows two variables "m" and "b" with values set to 1.*
|
||||||
|
9. Adjust the value, minimum, maximum, and step for each variable <br>
|
||||||
|
*Expected: y=mx+b graph adjusts to the new values for m and b, step size changes the increments of the slider for each value*
|
||||||
|
10. Share the graph via OneNote, Outlook/Mail, Twitter, and Feedback Hub <br>
|
||||||
|
*Expected: Modifiable message that contains an image of the graph customized for the chosen application opens*
|
||||||
|
11. Verify Key Graph Features tab shows the correct information for the following functions: <br>
|
||||||
|
*(Note: IP = Inflection Points, VA = Vertical Asymptotes, HA = Horizontal Asymptotes, OA = Oblique Asymptotes)* <br>
|
||||||
|
a. **y=x** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: ⁅y∈ℝ⁆; X/Y Intercepts: (0)/(0); Max: none; Min: none; IP: none; VA: none; HA: none; OA: none; Parity: Odd; Monotonicity: (-∞, ∞) Increasing* <br>
|
||||||
|
b. **y=1/x** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥≠0⁆; Range: ⁅y∈ℝ\{0}⁆; X/Y Intercepts: ø/ø; Max: none; Min: none; IP: none; VA: x=0; HA: y=0; OA: none; Parity: Odd; Monotonicity: (0, ∞) Decreasing, (-∞, 0) Increasing* <br>
|
||||||
|
c. **y=x^2** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: ⁅y∈{0, ∞)⁆; X/Y Intercepts: (0)/(0); Max: none; Min: (0,0); IP: none; VA: none; HA: none; OA: none; Parity: Even; Monotonicity: (0, ∞) Increasing, (-∞, 0) Decreasing* <br>
|
||||||
|
d. **y=x^3** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: ⁅y∈ℝ⁆; X/Y Intercepts: (0)/(0); Max: none; Min: none; IP: (0,0); VA: none; HA: none; OA: none; Parity: Odd; Monotonicity: (-∞, ∞) Increasing* <br>
|
||||||
|
e. **y=e^x** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: ⁅y∈(0, ∞)⁆; X/Y Intercepts: ø/(1); Max: none; Min: none; IP: none; VA: none; HA: y=0; OA: none; Parity: none; Monotonicity: (-∞, ∞) Increasing* <br>
|
||||||
|
f. **y=ln(x)** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥>0⁆; Range: ⁅y∈ℝ⁆; X/Y Intercepts: (1)/ø; Max: none; Min: none; IP: none; VA: x=0; HA: none; OA: none; Parity: none; Monotonicity: (0, ∞) Increasing* <br>
|
||||||
|
g. **y=sin(x)** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: ⁅𝑦∈[−1,1]⁆; X/Y Intercepts: (⁅𝜋n1,n1∈ℤ⁆)/(0); Max: ⁅(2𝜋n1+𝜋/2,1),n1∈ℤ⁆; Min: ⁅(2𝜋n1+3𝜋/2,−1),n1∈ℤ⁆; IP: ⁅(𝜋n1,0),n1∈ℤ⁆; VA: none; HA: none; OA: none; Parity: Odd; Monotonicity: ⁅(2𝜋n1+𝜋/2,2𝜋n1+3𝜋/2),n1∈ℤ⁆ Decreasing; ⁅(2𝜋n1+3𝜋/2,2𝜋n1+5𝜋/2),n1∈ℤ⁆ Increasing; Period: 2𝜋* <br>
|
||||||
|
h. **y=cos(x)** <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: ⁅𝑦∈[−1,1]⁆; X/Y Intercepts: (⁅𝜋n1+𝜋/2,n1∈ℤ⁆)/(1); Max: ⁅(2𝜋n1,1),n1∈ℤ⁆; Min: ⁅(2𝜋n1+𝜋,-1),n1∈ℤ⁆; IP: ⁅(𝜋n1+𝜋/2,0),n1∈ℤ⁆; VA: none; HA: none; OA: none; Parity: Even; Monotonicity: ⁅(2𝜋n1+𝜋,2𝜋n1+2𝜋),n1∈ℤ⁆ Increasing, ⁅(2𝜋n1,2𝜋n1+𝜋),n1∈ℤ⁆ Decreasing; Period: 2𝜋* <br>
|
||||||
|
i. **y=tan(x)** <br>
|
||||||
|
*Expected: Domain: ⁅x≠𝜋n1+𝜋/2,∀n1∈ℤ⁆; Range: ⁅𝑦∈ℝ⁆; X/Y Intercepts: (x=𝜋n1, n1 ∈ℤ)/(0); Max: none; Min: none; IP: x=𝜋n1, n1 ∈ℤ; VA: x=𝜋n1+𝜋/2, n1∈ℤ; HA: none; OA: none; Parity: Odd; Monotonicity: ⁅(𝜋n1+𝜋/2,𝜋n1+3𝜋/2),n1∈ℤ⁆ Increasing; Period: 𝜋* <br>
|
||||||
|
j. **y=sqrt(25-x^2)** <br>
|
||||||
|
*Expected: Domain: ⁅x∈[-5,5]⁆; Range: ⁅𝑦∈[0,5]⁆; X/Y Intercepts: (5),(-5)/(5); Max: (0,5); Min: (-5,0) and (5,0); IP: none; VA: none; HA: none; OA: none; Parity: Even; Monotonicity: (0,5) Decreasing, (-5,0) Increasing* <br>
|
||||||
|
k. **y=(-3x^2+2)/(x-1)** <br>
|
||||||
|
*Expected: Domain: ⁅x≠1⁆; Range: ⁅𝑦∈(-∞, -2√3 - 6}U{2√3 -6,∞⁆; X/Y Intercepts: (-√6/3),(√6/3)/(-2); Max: ⁅(√3/3+1,-2√3−6)⁆; Min: ⁅(−√3/3+1,2√3−6)⁆; IP: none; VA: x=1; HA: none; OA: y=-3x-3; Parity: none; Monotonicity: (√3/3+1,∞) Decreasing, (1,√3/3+1,) Increasing(-√3/3+1,1), Increasing, (-∞,-√3/3+1) Decreasing* <br>
|
||||||
|
l. **y=sin(sin(x))** ("too complex" error test) <br>
|
||||||
|
*Expected: Domain: ⁅𝑥∈ℝ⁆; Range: Unable to calculate range for this function; X/Y Intercepts: none; Max: none; Min: none; IP: none; VA: none; HA: none; OA: none; Parity: odd; Monotonicity: Unable to determine the monotonicity of the function* <br>
|
||||||
|
*These features are too complex for Calculator to calculate: Range, X Intercept, Period, Minima, Maxima, Inflection Points, Monotonicity*
|
||||||
|
m. **y=mx+b** <br>
|
||||||
|
*Expected: Analysis is not supported for this function*
|
||||||
|
|
||||||
**Date Calculation Test: Verify dates can be calculated.**
|
**Date Calculation Test: Verify dates can be calculated.**
|
||||||
Steps:
|
Steps:
|
||||||
1. Launch the "Calculator" app.
|
1. Launch the "Calculator" app
|
||||||
2. Navigate to "Date Calculation" Calculator.
|
2. Navigate to "Date Calculation" Calculator
|
||||||
3. With "Difference between dates" Selected
|
3. With "Difference between dates" Selected
|
||||||
Change the various date input fields
|
Change the various date input fields
|
||||||
*Expected: From and To reflect dates input respectively.*
|
*Expected: From and To reflect dates input respectively.*
|
||||||
|
@ -332,80 +383,88 @@ Steps:
|
||||||
1. Launch the "Calculator" app.
|
1. Launch the "Calculator" app.
|
||||||
|
|
||||||
For All Applicable Modes verify the following (note: only 11-15 and 20 work in Always-on-Top mode):
|
For All Applicable Modes verify the following (note: only 11-15 and 20 work in Always-on-Top mode):
|
||||||
2. Press **Alt +1** to Enter "Standard" mode
|
2. Press **Alt +1** to enter "Standard" mode
|
||||||
*Expected: Move to "Standard" screen.*
|
*Expected: Move to "Standard" screen.*
|
||||||
3. Press **Alt +2** to Enter "Scientific" mode
|
3. Press **Alt +2** to enter "Scientific" mode
|
||||||
*Expected: Move to "Scientific" screen.*
|
*Expected: Move to "Scientific" screen.*
|
||||||
4. Press **Alt +3** to Enter "Programmer" mode
|
4. Press **Alt +3** to enter "Programmer" mode
|
||||||
*Expected: Move to "Programming" screen.*
|
*Expected: Move to "Programming" screen.*
|
||||||
5. Press **Alt +4** to Enter "Date Calculation" mode
|
5. Press **Alt +4** to enter "Date Calculation" mode
|
||||||
*Expected: Move to "Date Calculation" screen.*
|
*Expected: Move to "Date Calculation" screen.*
|
||||||
6. Press **Ctrl +M** to Store in Memory
|
6 Press **Alt +5** to enter "Graphing" mode
|
||||||
7. Press **Ctrl +P** to Add to Active Memory
|
*Expected: Move to "Graphing" screen.*
|
||||||
8. Press **Ctrl +Q** to Subtract form Active Memory
|
7. Press **Ctrl +M** to Store in Memory
|
||||||
9. Press **Ctrl +R** to Recall from Memory
|
8. Press **Ctrl +P** to Add to Active Memory
|
||||||
10. Press **Ctrl +L** to Clear from Memory
|
9. Press **Ctrl +Q** to Subtract form Active Memory
|
||||||
11. Press **Delete** to Clear Current Input 'CE'
|
10. Press **Ctrl +R** to Recall from Memory
|
||||||
12. Press **Esc** to Full Clear Input 'C'
|
11. Press **Ctrl +L** to Clear from Memory
|
||||||
13. Press **F9** to Toggle '±'
|
12. Press **Delete** to Clear Current Input 'CE'
|
||||||
14. Press **R** to Select '1/x'
|
13. Press **Esc** to Full Clear Input 'C'
|
||||||
15. Press **@** to Select '√'
|
14. Press **F9** to Toggle '±'
|
||||||
16. Press **Ctrl + H** to Toggle History Panel
|
15. Press **R** to Select '1/x'
|
||||||
|
16. Press **@** to Select '√'
|
||||||
|
17. Press **Ctrl + H** to Toggle History Panel
|
||||||
*Expected: Function when in small scale window.*
|
*Expected: Function when in small scale window.*
|
||||||
17. Press **Up arrow** to Move up History Panel
|
18. Press **Up arrow** to Move up History Panel
|
||||||
*Expected: Function when in small scale window.*
|
*Expected: Function when in small scale window.*
|
||||||
18. Press **Down arrow** to Move Down History Panel
|
19. Press **Down arrow** to Move Down History Panel
|
||||||
*Expected: Function when in small scale window.*
|
*Expected: Function when in small scale window.*
|
||||||
19. Press **Ctrl + Shift + D** to Clear History Panel
|
20. Press **Ctrl + Shift + D** to Clear History Panel
|
||||||
*Expected: Function when in small scale window.*
|
*Expected: Function when in small scale window.*
|
||||||
20. Press **Spacebar** to Repeat Last Input
|
21. Press **Spacebar** to Repeat Last Input
|
||||||
|
|
||||||
Verify the following in Scientific Mode
|
Verify the following in Scientific Mode
|
||||||
21. Press **F3** to Select 'DEG'
|
22. Press **F3** to Select 'DEG'
|
||||||
22. Press **F4** to Select 'RAD'
|
23. Press **F4** to Select 'RAD'
|
||||||
23. Press **F5** to Select 'GRAD'
|
24. Press **F5** to Select 'GRAD'
|
||||||
24. Press **Ctrl +G** to Select '10ˣ'
|
25. Press **Ctrl +G** to Select '10ˣ'
|
||||||
25. Press **Ctrl +Y** to Select 'y√x'
|
26. Press **Ctrl +Y** to Select 'y√x'
|
||||||
26. Press **Shift +O** to Select 'sin-1'
|
27. Press **Shift +O** to Select 'sin-1'
|
||||||
27. Press **Shift + S** to Select 'cos-1'
|
28. Press **Shift + S** to Select 'cos-1'
|
||||||
28. Press **Shift +T** to Select 'tan-1'
|
29. Press **Shift +T** to Select 'tan-1'
|
||||||
29. Press **Ctrl +O** to Select 'Cosh'
|
30. Press **Ctrl +O** to Select 'Cosh'
|
||||||
30. Press **Ctrl +S** to Select 'Sinh'
|
31. Press **Ctrl +S** to Select 'Sinh'
|
||||||
31. Press **Ctrl +T** to Select 'Tanh'
|
32. Press **Ctrl +T** to Select 'Tanh'
|
||||||
32. Press **D** to Select 'Mod'
|
33. Press **D** to Select 'Mod'
|
||||||
33. Press **L** to Select 'log'
|
34. Press **L** to Select 'log'
|
||||||
34. Press **M** to Select 'dms'
|
35. Press **M** to Select 'dms'
|
||||||
35. Press **N** to Select 'ln'
|
36. Press **N** to Select 'ln'
|
||||||
36. Press **Ctrl +N** to Select 'ex'
|
37. Press **Ctrl +N** to Select 'ex'
|
||||||
37. Press **O** to Select 'Cos'
|
38. Press **O** to Select 'Cos'
|
||||||
38. Press **P** to Select 'π'
|
39. Press **P** to Select 'π'
|
||||||
39. Press **Q** to Select 'x²'
|
40. Press **Q** to Select 'x²'
|
||||||
40. Press **S** to Select 'Sin'
|
41. Press **S** to Select 'Sin'
|
||||||
41. Press **T** to Select 'Tan'
|
42. Press **T** to Select 'Tan'
|
||||||
42. Press **V** to Toggle 'F-E'
|
43. Press **V** to Toggle 'F-E'
|
||||||
43. Press **X** to Select 'Exp'
|
44. Press **X** to Select 'Exp'
|
||||||
44. Press **Y** or **^** to Select 'xʸ'
|
45. Press **Y** or **^** to Select 'xʸ'
|
||||||
45. Press **#** to Select 'x³'
|
46. Press **#** to Select 'x³'
|
||||||
46. Press **!** to Select 'n!'
|
47. Press **!** to Select 'n!'
|
||||||
|
|
||||||
Verify the following in Programmer Mode
|
Verify the following in Programmer Mode
|
||||||
47. Press **F2** to Select 'DWORD'
|
48. Press **F2** to Select 'DWORD'
|
||||||
48. Press **F3** to Select 'WORD'
|
49. Press **F3** to Select 'WORD'
|
||||||
49. Press **F4** to Select 'BYTE'
|
50. Press **F4** to Select 'BYTE'
|
||||||
50. Press **F5** to Select 'HEX'
|
51. Press **F5** to Select 'HEX'
|
||||||
51. Press **F6** to Select 'DEC'
|
52. Press **F6** to Select 'DEC'
|
||||||
52. Press **F7** to Select 'OCT'
|
53. Press **F7** to Select 'OCT'
|
||||||
53. Press **F8** to Select 'BIN'
|
54. Press **F8** to Select 'BIN'
|
||||||
54. Press **F12** to Select 'QWORD'
|
55. Press **F12** to Select 'QWORD'
|
||||||
55. Press **A-F** to Input in HEX
|
56. Press **A-F** to Input in HEX
|
||||||
56. Press **J** to Select 'RoL'
|
57. Press **J** to Select 'RoL'
|
||||||
57. Press **K** to Select 'RoR'
|
58. Press **K** to Select 'RoR'
|
||||||
58. Press **<** to Select 'Lsh'
|
59. Press **<** to Select 'Lsh'
|
||||||
59. Press **>** to Select 'Rsh'
|
60. Press **>** to Select 'Rsh'
|
||||||
60. Press **%** to Select 'Mod'
|
61. Press **%** to Select 'Mod'
|
||||||
61. Press **|** to Select 'Or'
|
62. Press **|** to Select 'Or'
|
||||||
62. Press **~** to Select 'Not'
|
63. Press **~** to Select 'Not'
|
||||||
63. Press **&** to Select 'And'
|
64. Press **&** to Select 'And'
|
||||||
|
|
||||||
|
Verify the following in Graphing Mode
|
||||||
|
65. Press **x** to Select 'x'
|
||||||
|
66. Press **y** to Select 'y'
|
||||||
|
67. Press **Ctrl +[Numpad+]** to Select 'Zoom In'
|
||||||
|
68. Press **Ctrl +[Numpad-]** to Select 'Zoom Out'
|
||||||
|
|
||||||
## Localization Tests
|
## Localization Tests
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,12 @@ Windows Calculator is under active development by Microsoft.
|
||||||
|
|
||||||
## Focus
|
## Focus
|
||||||
|
|
||||||
In 2019, the Windows Calculator team is focused on:
|
In 2020, the Windows Calculator team is focused on:
|
||||||
* Refining our open source development process on GitHub
|
* Iterating upon the existing app design based on the latest guidelines for [Fluent Design](https://developer.microsoft.com/en-us/windows/apps/design), [Windows 10X dual-screen devices](https://docs.microsoft.com/en-us/dual-screen/windows/), and [WinUI 3.0](https://github.com/microsoft/microsoft-ui-xaml).
|
||||||
* Iterating upon the existing app design based on the latest [Fluent Design guidelines](https://developer.microsoft.com/en-us/windows/apps/design)
|
* Unblocking community contributions by identifying and addressing bottlenecks affecting developers, including migrating portions of the codebase to C# ([#893](https://github.com/microsoft/calculator/issues/893)) and adding a settings page ([#596](https://github.com/microsoft/calculator/issues/596)).
|
||||||
* Improving testing and diagnostics within the project
|
* Addressing top user pain points, including clearing up confusion around how Standard Calculator behaves ([#138](https://github.com/microsoft/calculator/issues/138)) and fixing hidden characters in copied results ([#504](https://github.com/microsoft/calculator/issues/504)).
|
||||||
* Investigating new features with a focus on addressing top user feedback, including:
|
* Investigating unit converter improvements ([#379](https://github.com/microsoft/calculator/issues/379), [#589](https://github.com/microsoft/calculator/issues/589) and [#594](https://github.com/microsoft/calculator/issues/594))
|
||||||
* Adding graphing mode
|
* [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started!
|
||||||
* Adding the ability for users to pin Calculator on top of other windows
|
|
||||||
* Providing additional customization options
|
|
||||||
* [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started!
|
|
||||||
|
|
||||||
We welcome contributions of all kinds from the community, but especially those that support the efforts above. Please see our [contributing guidelines](https://github.com/Microsoft/calculator/blob/master/CONTRIBUTING.md) for more information on how to get involved.
|
We welcome contributions of all kinds from the community, but especially those that support the efforts above. Please see our [contributing guidelines](https://github.com/Microsoft/calculator/blob/master/CONTRIBUTING.md) for more information on how to get involved.
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(calculator CXX)
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER MATCHES ".*clang")
|
|
||||||
# Clang disagress with libstdc++ about constexpr-ness of wstring_view
|
|
||||||
# See https://github.com/Microsoft/calculator/pull/321
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(CalcManager)
|
|
|
@ -1,14 +0,0 @@
|
||||||
target_sources(CalcManager PRIVATE
|
|
||||||
calc.cpp
|
|
||||||
CalcInput.cpp
|
|
||||||
CalcUtils.cpp
|
|
||||||
History.cpp
|
|
||||||
Number.cpp
|
|
||||||
Rational.cpp
|
|
||||||
RationalMath.cpp
|
|
||||||
scicomm.cpp
|
|
||||||
scidisp.cpp
|
|
||||||
scifunc.cpp
|
|
||||||
scioper.cpp
|
|
||||||
sciset.cpp
|
|
||||||
)
|
|
|
@ -210,7 +210,7 @@ bool CHistoryCollector::FOpndAddedToHistory()
|
||||||
// This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt),
|
// This is does the postfix to prefix translation of the input and adds the text to the history. Eg. doing 2 + 4 (sqrt),
|
||||||
// this routine will ensure the last sqrt call unary operator, actually goes back in history and wraps 4 in sqrt(4)
|
// this routine will ensure the last sqrt call unary operator, actually goes back in history and wraps 4 in sqrt(4)
|
||||||
//
|
//
|
||||||
void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype)
|
void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, AngleType angletype)
|
||||||
{
|
{
|
||||||
int iCommandEnd;
|
int iCommandEnd;
|
||||||
// When successfully applying a unary op, there should be an opnd already
|
// When successfully applying a unary op, there should be an opnd already
|
||||||
|
@ -230,15 +230,15 @@ void CHistoryCollector::AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE a
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CalculationManager::Command angleOpCode;
|
CalculationManager::Command angleOpCode;
|
||||||
if (angletype == ANGLE_DEG)
|
if (angletype == AngleType::Degrees)
|
||||||
{
|
{
|
||||||
angleOpCode = CalculationManager::Command::CommandDEG;
|
angleOpCode = CalculationManager::Command::CommandDEG;
|
||||||
}
|
}
|
||||||
else if (angletype == ANGLE_RAD)
|
else if (angletype == AngleType::Radians)
|
||||||
{
|
{
|
||||||
angleOpCode = CalculationManager::Command::CommandRAD;
|
angleOpCode = CalculationManager::Command::CommandRAD;
|
||||||
}
|
}
|
||||||
else // (angletype == ANGLE_GRAD)
|
else // (angletype == AngleType::Gradians)
|
||||||
{
|
{
|
||||||
angleOpCode = CalculationManager::Command::CommandGRAD;
|
angleOpCode = CalculationManager::Command::CommandGRAD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -460,7 +460,7 @@ namespace CalcEngine
|
||||||
return !(lhs < rhs);
|
return !(lhs < rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring Rational::ToString(uint32_t radix, NUMOBJ_FMT fmt, int32_t precision) const
|
wstring Rational::ToString(uint32_t radix, NumberFormat fmt, int32_t precision) const
|
||||||
{
|
{
|
||||||
PRAT rat = this->ToPRAT();
|
PRAT rat = this->ToPRAT();
|
||||||
wstring result{};
|
wstring result{};
|
||||||
|
|
|
@ -147,7 +147,7 @@ Rational RationalMath::Abs(Rational const& rat)
|
||||||
return Rational{ Number{ 1, rat.P().Exp(), rat.P().Mantissa() }, Number{ 1, rat.Q().Exp(), rat.Q().Mantissa() } };
|
return Rational{ Number{ 1, rat.P().Exp(), rat.P().Mantissa() }, Number{ 1, rat.Q().Exp(), rat.Q().Mantissa() } };
|
||||||
}
|
}
|
||||||
|
|
||||||
Rational RationalMath::Sin(Rational const& rat, ANGLE_TYPE angletype)
|
Rational RationalMath::Sin(Rational const& rat, AngleType angletype)
|
||||||
{
|
{
|
||||||
PRAT prat = rat.ToPRAT();
|
PRAT prat = rat.ToPRAT();
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ Rational RationalMath::Sin(Rational const& rat, ANGLE_TYPE angletype)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rational RationalMath::Cos(Rational const& rat, ANGLE_TYPE angletype)
|
Rational RationalMath::Cos(Rational const& rat, AngleType angletype)
|
||||||
{
|
{
|
||||||
PRAT prat = rat.ToPRAT();
|
PRAT prat = rat.ToPRAT();
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ Rational RationalMath::Cos(Rational const& rat, ANGLE_TYPE angletype)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rational RationalMath::Tan(Rational const& rat, ANGLE_TYPE angletype)
|
Rational RationalMath::Tan(Rational const& rat, AngleType angletype)
|
||||||
{
|
{
|
||||||
PRAT prat = rat.ToPRAT();
|
PRAT prat = rat.ToPRAT();
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ Rational RationalMath::Tan(Rational const& rat, ANGLE_TYPE angletype)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rational RationalMath::ASin(Rational const& rat, ANGLE_TYPE angletype)
|
Rational RationalMath::ASin(Rational const& rat, AngleType angletype)
|
||||||
{
|
{
|
||||||
PRAT prat = rat.ToPRAT();
|
PRAT prat = rat.ToPRAT();
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ Rational RationalMath::ASin(Rational const& rat, ANGLE_TYPE angletype)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rational RationalMath::ACos(Rational const& rat, ANGLE_TYPE angletype)
|
Rational RationalMath::ACos(Rational const& rat, AngleType angletype)
|
||||||
{
|
{
|
||||||
PRAT prat = rat.ToPRAT();
|
PRAT prat = rat.ToPRAT();
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ Rational RationalMath::ACos(Rational const& rat, ANGLE_TYPE angletype)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rational RationalMath::ATan(Rational const& rat, ANGLE_TYPE angletype)
|
Rational RationalMath::ATan(Rational const& rat, AngleType angletype)
|
||||||
{
|
{
|
||||||
PRAT prat = rat.ToPRAT();
|
PRAT prat = rat.ToPRAT();
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ CCalcEngine::CCalcEngine(
|
||||||
, m_bRecord(false)
|
, m_bRecord(false)
|
||||||
, m_bSetCalcState(false)
|
, m_bSetCalcState(false)
|
||||||
, m_input(DEFAULT_DEC_SEPARATOR)
|
, m_input(DEFAULT_DEC_SEPARATOR)
|
||||||
, m_nFE(FMT_FLOAT)
|
, m_nFE(NumberFormat::Float)
|
||||||
, m_memoryValue{ make_unique<Rational>() }
|
, m_memoryValue{ make_unique<Rational>() }
|
||||||
, m_holdVal{}
|
, m_holdVal{}
|
||||||
, m_currentVal{}
|
, m_currentVal{}
|
||||||
|
@ -94,8 +94,8 @@ CCalcEngine::CCalcEngine(
|
||||||
, m_nPrecOp()
|
, m_nPrecOp()
|
||||||
, m_precedenceOpCount(0)
|
, m_precedenceOpCount(0)
|
||||||
, m_nLastCom(0)
|
, m_nLastCom(0)
|
||||||
, m_angletype(ANGLE_DEG)
|
, m_angletype(AngleType::Degrees)
|
||||||
, m_numwidth(QWORD_WIDTH)
|
, m_numwidth(NUM_WIDTH::QWORD_WIDTH)
|
||||||
, m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR)
|
, m_HistoryCollector(pCalcDisplay, pHistoryDisplay, DEFAULT_DEC_SEPARATOR)
|
||||||
, m_groupSeparator(DEFAULT_GRP_SEPARATOR)
|
, m_groupSeparator(DEFAULT_GRP_SEPARATOR)
|
||||||
{
|
{
|
||||||
|
@ -105,7 +105,7 @@ CCalcEngine::CCalcEngine(
|
||||||
|
|
||||||
m_maxTrigonometricNum = RationalMath::Pow(10, 100);
|
m_maxTrigonometricNum = RationalMath::Pow(10, 100);
|
||||||
|
|
||||||
SetRadixTypeAndNumWidth(DEC_RADIX, m_numwidth);
|
SetRadixTypeAndNumWidth(RadixType::Decimal, m_numwidth);
|
||||||
SettingsChanged();
|
SettingsChanged();
|
||||||
DisplayNum();
|
DisplayNum();
|
||||||
}
|
}
|
||||||
|
@ -128,10 +128,20 @@ void CCalcEngine::InitChopNumbers()
|
||||||
auto maxVal = m_chopNumbers[i] / 2;
|
auto maxVal = m_chopNumbers[i] / 2;
|
||||||
maxVal = RationalMath::Integer(maxVal);
|
maxVal = RationalMath::Integer(maxVal);
|
||||||
|
|
||||||
m_maxDecimalValueStrings[i] = maxVal.ToString(10, FMT_FLOAT, m_precision);
|
m_maxDecimalValueStrings[i] = maxVal.ToString(10, NumberFormat::Float, m_precision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CalcEngine::Rational CCalcEngine::GetChopNumber() const
|
||||||
|
{
|
||||||
|
return m_chopNumbers[static_cast<int>(m_numwidth)];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring CCalcEngine::GetMaxDecimalValueString() const
|
||||||
|
{
|
||||||
|
return m_maxDecimalValueStrings[static_cast<int>(m_numwidth)];
|
||||||
|
}
|
||||||
|
|
||||||
// Gets the number in memory for UI to keep it persisted and set it again to a different instance
|
// Gets the number in memory for UI to keep it persisted and set it again to a different instance
|
||||||
// of CCalcEngine. Otherwise it will get destructed with the CalcEngine
|
// of CCalcEngine. Otherwise it will get destructed with the CalcEngine
|
||||||
unique_ptr<Rational> CCalcEngine::PersistedMemObject()
|
unique_ptr<Rational> CCalcEngine::PersistedMemObject()
|
||||||
|
|
|
@ -35,20 +35,17 @@ namespace
|
||||||
IDC_ADD,2, IDC_SUB,2,
|
IDC_ADD,2, IDC_SUB,2,
|
||||||
IDC_RSHF,3, IDC_LSHF,3, IDC_RSHFL,3,
|
IDC_RSHF,3, IDC_LSHF,3, IDC_RSHFL,3,
|
||||||
IDC_MOD,3, IDC_DIV,3, IDC_MUL,3,
|
IDC_MOD,3, IDC_DIV,3, IDC_MUL,3,
|
||||||
IDC_PWR,4, IDC_ROOT,4, IDC_LOGBASEX,4 };
|
IDC_PWR,4, IDC_ROOT,4, IDC_LOGBASEY,4 };
|
||||||
unsigned int iPrec;
|
|
||||||
|
|
||||||
iPrec = 0;
|
for (unsigned int iPrec = 0; iPrec < size(rgbPrec); iPrec += 2)
|
||||||
while ((iPrec < size(rgbPrec)) && (nopCode != rgbPrec[iPrec]))
|
|
||||||
{
|
{
|
||||||
iPrec += 2;
|
if (nopCode == rgbPrec[iPrec])
|
||||||
}
|
|
||||||
if (iPrec >= size(rgbPrec))
|
|
||||||
{
|
{
|
||||||
iPrec = 0;
|
|
||||||
}
|
|
||||||
return rgbPrec[iPrec + 1];
|
return rgbPrec[iPrec + 1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleErrorCommand
|
// HandleErrorCommand
|
||||||
|
@ -104,8 +101,6 @@ void CCalcEngine::ProcessCommand(OpCode wParam)
|
||||||
|
|
||||||
void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
{
|
{
|
||||||
int nx, ni;
|
|
||||||
|
|
||||||
// Save the last command. Some commands are not saved in this manor, these
|
// Save the last command. Some commands are not saved in this manor, these
|
||||||
// commands are:
|
// commands are:
|
||||||
// Inv, Deg, Rad, Grad, Stat, FE, MClear, Back, and Exp. The excluded
|
// Inv, Deg, Rad, Grad, Stat, FE, MClear, Back, and Exp. The excluded
|
||||||
|
@ -163,15 +158,12 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
|
DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (IsDigitOpCode(wParam) || wParam == IDC_PNT)
|
||||||
{
|
|
||||||
if (IsDigitOpCode(wParam) || wParam == IDC_PNT)
|
|
||||||
{
|
{
|
||||||
m_bRecord = true;
|
m_bRecord = true;
|
||||||
m_input.Clear();
|
m_input.Clear();
|
||||||
CheckAndAddLastBinOpToHistory();
|
CheckAndAddLastBinOpToHistory();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Interpret digit keys.
|
// Interpret digit keys.
|
||||||
if (IsDigitOpCode(wParam))
|
if (IsDigitOpCode(wParam))
|
||||||
|
@ -185,7 +177,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_input.TryAddDigit(iValue, m_radix, m_fIntegerMode, m_maxDecimalValueStrings[m_numwidth], m_dwWordBitWidth, m_cIntDigitsSav))
|
if (!m_input.TryAddDigit(iValue, m_radix, m_fIntegerMode, GetMaxDecimalValueString(), m_dwWordBitWidth, m_cIntDigitsSav))
|
||||||
{
|
{
|
||||||
HandleErrorCommand(wParam);
|
HandleErrorCommand(wParam);
|
||||||
HandleMaxDigitsReached();
|
HandleMaxDigitsReached();
|
||||||
|
@ -203,7 +195,6 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
// Change the operation if last input was operation.
|
// Change the operation if last input was operation.
|
||||||
if (IsBinOpCode(m_nLastCom))
|
if (IsBinOpCode(m_nLastCom))
|
||||||
{
|
{
|
||||||
int nPrev;
|
|
||||||
bool fPrecInvToHigher = false; // Is Precedence Inversion from lower to higher precedence happening ??
|
bool fPrecInvToHigher = false; // Is Precedence Inversion from lower to higher precedence happening ??
|
||||||
|
|
||||||
m_nOpCode = (int)wParam;
|
m_nOpCode = (int)wParam;
|
||||||
|
@ -214,9 +205,9 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
// Here * is m_nPrevOpCode, m_currentVal is 2 (by 1*2), m_nLastCom is +, m_nOpCode is ^
|
// Here * is m_nPrevOpCode, m_currentVal is 2 (by 1*2), m_nLastCom is +, m_nOpCode is ^
|
||||||
if (m_fPrecedence && 0 != m_nPrevOpCode)
|
if (m_fPrecedence && 0 != m_nPrevOpCode)
|
||||||
{
|
{
|
||||||
nPrev = NPrecedenceOfOp(m_nPrevOpCode);
|
int nPrev = NPrecedenceOfOp(m_nPrevOpCode);
|
||||||
nx = NPrecedenceOfOp(m_nLastCom);
|
int nx = NPrecedenceOfOp(m_nLastCom);
|
||||||
ni = NPrecedenceOfOp(m_nOpCode);
|
int ni = NPrecedenceOfOp(m_nOpCode);
|
||||||
if (nx <= nPrev && ni > nPrev) // condition for Precedence Inversion
|
if (nx <= nPrev && ni > nPrev) // condition for Precedence Inversion
|
||||||
{
|
{
|
||||||
fPrecInvToHigher = true;
|
fPrecInvToHigher = true;
|
||||||
|
@ -243,8 +234,8 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
{
|
{
|
||||||
DoPrecedenceCheckAgain:
|
DoPrecedenceCheckAgain:
|
||||||
|
|
||||||
nx = NPrecedenceOfOp((int)wParam);
|
int nx = NPrecedenceOfOp((int)wParam);
|
||||||
ni = NPrecedenceOfOp(m_nOpCode);
|
int ni = NPrecedenceOfOp(m_nOpCode);
|
||||||
|
|
||||||
if ((nx > ni) && m_fPrecedence)
|
if ((nx > ni) && m_fPrecedence)
|
||||||
{
|
{
|
||||||
|
@ -492,8 +483,8 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
m_lastVal = m_precedenceVals[m_precedenceOpCount];
|
m_lastVal = m_precedenceVals[m_precedenceOpCount];
|
||||||
|
|
||||||
// Precedence Inversion check
|
// Precedence Inversion check
|
||||||
ni = NPrecedenceOfOp(m_nPrevOpCode);
|
int ni = NPrecedenceOfOp(m_nPrevOpCode);
|
||||||
nx = NPrecedenceOfOp(m_nOpCode);
|
int nx = NPrecedenceOfOp(m_nOpCode);
|
||||||
if (ni <= nx)
|
if (ni <= nx)
|
||||||
{
|
{
|
||||||
m_HistoryCollector.EnclosePrecInversionBrackets();
|
m_HistoryCollector.EnclosePrecInversionBrackets();
|
||||||
|
@ -518,20 +509,15 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
|
|
||||||
case IDC_OPENP:
|
case IDC_OPENP:
|
||||||
case IDC_CLOSEP:
|
case IDC_CLOSEP:
|
||||||
nx = 0;
|
|
||||||
if (wParam == IDC_OPENP)
|
|
||||||
{
|
|
||||||
nx = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -IF- the Paren holding array is full and we try to add a paren
|
// -IF- the Paren holding array is full and we try to add a paren
|
||||||
// -OR- the paren holding array is empty and we try to remove a
|
// -OR- the paren holding array is empty and we try to remove a
|
||||||
// paren
|
// paren
|
||||||
// -OR- the precedence holding array is full
|
// -OR- the precedence holding array is full
|
||||||
if ((m_openParenCount >= MAXPRECDEPTH && nx) || (!m_openParenCount && !nx)
|
if ((m_openParenCount >= MAXPRECDEPTH && (wParam == IDC_OPENP)) || (!m_openParenCount && (wParam != IDC_OPENP))
|
||||||
|| ((m_precedenceOpCount >= MAXPRECDEPTH && m_nPrecOp[m_precedenceOpCount - 1] != 0)))
|
|| ((m_precedenceOpCount >= MAXPRECDEPTH && m_nPrecOp[m_precedenceOpCount - 1] != 0)))
|
||||||
{
|
{
|
||||||
if (!m_openParenCount && !nx)
|
if (!m_openParenCount && (wParam != IDC_OPENP))
|
||||||
{
|
{
|
||||||
m_pCalcDisplay->OnNoRightParenAdded();
|
m_pCalcDisplay->OnNoRightParenAdded();
|
||||||
}
|
}
|
||||||
|
@ -540,7 +526,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nx)
|
if (wParam == IDC_OPENP)
|
||||||
{
|
{
|
||||||
CheckAndAddLastBinOpToHistory();
|
CheckAndAddLastBinOpToHistory();
|
||||||
m_HistoryCollector.AddOpenBraceToHistory();
|
m_HistoryCollector.AddOpenBraceToHistory();
|
||||||
|
@ -588,8 +574,8 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
for (m_nOpCode = m_nPrecOp[--m_precedenceOpCount]; m_nOpCode; m_nOpCode = m_nPrecOp[--m_precedenceOpCount])
|
for (m_nOpCode = m_nPrecOp[--m_precedenceOpCount]; m_nOpCode; m_nOpCode = m_nPrecOp[--m_precedenceOpCount])
|
||||||
{
|
{
|
||||||
// Precedence Inversion check
|
// Precedence Inversion check
|
||||||
ni = NPrecedenceOfOp(m_nPrevOpCode);
|
int ni = NPrecedenceOfOp(m_nPrevOpCode);
|
||||||
nx = NPrecedenceOfOp(m_nOpCode);
|
int nx = NPrecedenceOfOp(m_nOpCode);
|
||||||
if (ni <= nx)
|
if (ni <= nx)
|
||||||
{
|
{
|
||||||
m_HistoryCollector.EnclosePrecInversionBrackets();
|
m_HistoryCollector.EnclosePrecInversionBrackets();
|
||||||
|
@ -633,7 +619,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
case IDM_OCT:
|
case IDM_OCT:
|
||||||
case IDM_BIN:
|
case IDM_BIN:
|
||||||
{
|
{
|
||||||
SetRadixTypeAndNumWidth((RADIX_TYPE)(wParam - IDM_HEX), (NUM_WIDTH)-1);
|
SetRadixTypeAndNumWidth((RadixType)(wParam - IDM_HEX), (NUM_WIDTH)-1);
|
||||||
m_HistoryCollector.UpdateHistoryExpression(m_radix, m_precision);
|
m_HistoryCollector.UpdateHistoryExpression(m_radix, m_precision);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -649,20 +635,20 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compat. mode BaseX: Qword, Dword, Word, Byte
|
// Compat. mode BaseX: Qword, Dword, Word, Byte
|
||||||
SetRadixTypeAndNumWidth((RADIX_TYPE)-1, (NUM_WIDTH)(wParam - IDM_QWORD));
|
SetRadixTypeAndNumWidth((RadixType)-1, (NUM_WIDTH)(wParam - IDM_QWORD));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDM_DEG:
|
case IDM_DEG:
|
||||||
case IDM_RAD:
|
case IDM_RAD:
|
||||||
case IDM_GRAD:
|
case IDM_GRAD:
|
||||||
m_angletype = static_cast<ANGLE_TYPE>(wParam - IDM_DEG);
|
m_angletype = static_cast<AngleType>(wParam - IDM_DEG);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_SIGN:
|
case IDC_SIGN:
|
||||||
{
|
{
|
||||||
if (m_bRecord)
|
if (m_bRecord)
|
||||||
{
|
{
|
||||||
if (m_input.TryToggleSign(m_fIntegerMode, m_maxDecimalValueStrings[m_numwidth]))
|
if (m_input.TryToggleSign(m_fIntegerMode, GetMaxDecimalValueString()))
|
||||||
{
|
{
|
||||||
DisplayNum();
|
DisplayNum();
|
||||||
}
|
}
|
||||||
|
@ -780,7 +766,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
|
||||||
break;
|
break;
|
||||||
case IDC_FE:
|
case IDC_FE:
|
||||||
// Toggle exponential notation display.
|
// Toggle exponential notation display.
|
||||||
m_nFE = NUMOBJ_FMT(!(int)m_nFE);
|
m_nFE = NumberFormat(!(int)m_nFE);
|
||||||
DisplayNum();
|
DisplayNum();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -962,7 +948,7 @@ static const std::unordered_map<int, FunctionNameElement> operatorStringTable =
|
||||||
{ IDC_SIGN, { SIDS_NEGATE } },
|
{ IDC_SIGN, { SIDS_NEGATE } },
|
||||||
{ IDC_DEGREES, { SIDS_DEGREES } },
|
{ IDC_DEGREES, { SIDS_DEGREES } },
|
||||||
{ IDC_POW2, { SIDS_TWOPOWX } },
|
{ IDC_POW2, { SIDS_TWOPOWX } },
|
||||||
{ IDC_LOGBASEX, { SIDS_LOGBASEX } },
|
{ IDC_LOGBASEY, { SIDS_LOGBASEY } },
|
||||||
{ IDC_ABS, { SIDS_ABS } },
|
{ IDC_ABS, { SIDS_ABS } },
|
||||||
{ IDC_CEIL, { SIDS_CEIL } },
|
{ IDC_CEIL, { SIDS_CEIL } },
|
||||||
{ IDC_FLOOR, { SIDS_FLOOR } },
|
{ IDC_FLOOR, { SIDS_FLOOR } },
|
||||||
|
@ -971,11 +957,11 @@ static const std::unordered_map<int, FunctionNameElement> operatorStringTable =
|
||||||
{ IDC_RSHFL, { SIDS_RSH } },
|
{ IDC_RSHFL, { SIDS_RSH } },
|
||||||
{ IDC_RORC, { SIDS_ROR } },
|
{ IDC_RORC, { SIDS_ROR } },
|
||||||
{ IDC_ROLC, { SIDS_ROL } },
|
{ IDC_ROLC, { SIDS_ROL } },
|
||||||
{ IDC_CUBEROOT, {SIDS_CUBEROOT} },
|
{ IDC_CUBEROOT, { SIDS_CUBEROOT } },
|
||||||
{ IDC_MOD, {SIDS_MOD, L"", L"", L"", L"", L"", SIDS_PROGRAMMER_MOD} },
|
{ IDC_MOD, { SIDS_MOD, L"", L"", L"", L"", L"", SIDS_PROGRAMMER_MOD } },
|
||||||
};
|
};
|
||||||
|
|
||||||
wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype)
|
wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, AngleType angletype)
|
||||||
{
|
{
|
||||||
// Try to lookup the ID in the UFNE table
|
// Try to lookup the ID in the UFNE table
|
||||||
wstring ids = L"";
|
wstring ids = L"";
|
||||||
|
@ -983,7 +969,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE
|
||||||
if (auto pair = operatorStringTable.find(nOpCode); pair != operatorStringTable.end())
|
if (auto pair = operatorStringTable.find(nOpCode); pair != operatorStringTable.end())
|
||||||
{
|
{
|
||||||
const FunctionNameElement& element = pair->second;
|
const FunctionNameElement& element = pair->second;
|
||||||
if (!element.hasAngleStrings || ANGLE_DEG == angletype)
|
if (!element.hasAngleStrings || AngleType::Degrees == angletype)
|
||||||
{
|
{
|
||||||
if (fInv)
|
if (fInv)
|
||||||
{
|
{
|
||||||
|
@ -995,7 +981,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE
|
||||||
ids = element.degreeString;
|
ids = element.degreeString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ANGLE_RAD == angletype)
|
else if (AngleType::Radians == angletype)
|
||||||
{
|
{
|
||||||
if (fInv)
|
if (fInv)
|
||||||
{
|
{
|
||||||
|
@ -1006,7 +992,7 @@ wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE
|
||||||
ids = element.radString;
|
ids = element.radString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ANGLE_GRAD == angletype)
|
else if (AngleType::Gradians == angletype)
|
||||||
{
|
{
|
||||||
if (fInv)
|
if (fInv)
|
||||||
{
|
{
|
||||||
|
@ -1059,7 +1045,7 @@ bool CCalcEngine::IsCurrentTooBigForTrig()
|
||||||
return m_currentVal >= m_maxTrigonometricNum;
|
return m_currentVal >= m_maxTrigonometricNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCalcEngine::GetCurrentRadix()
|
uint32_t CCalcEngine::GetCurrentRadix()
|
||||||
{
|
{
|
||||||
return m_radix;
|
return m_radix;
|
||||||
}
|
}
|
||||||
|
@ -1108,7 +1094,7 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix)
|
||||||
if ((radix == 10) && fMsb)
|
if ((radix == 10) && fMsb)
|
||||||
{
|
{
|
||||||
// If high bit is set, then get the decimal number in negative 2's complement form.
|
// If high bit is set, then get the decimal number in negative 2's complement form.
|
||||||
tempRat = -((tempRat ^ m_chopNumbers[m_numwidth]) + 1);
|
tempRat = -((tempRat ^ GetChopNumber()) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = tempRat.ToString(radix, m_nFE, m_precision);
|
result = tempRat.ToString(radix, m_nFE, m_precision);
|
||||||
|
|
|
@ -67,10 +67,10 @@ CalcEngine::Rational CCalcEngine::TruncateNumForIntMath(CalcEngine::Rational con
|
||||||
{
|
{
|
||||||
// if negative make positive by doing a twos complement
|
// if negative make positive by doing a twos complement
|
||||||
result = -(result)-1;
|
result = -(result)-1;
|
||||||
result ^= m_chopNumbers[m_numwidth];
|
result ^= GetChopNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
result &= m_chopNumbers[m_numwidth];
|
result &= GetChopNumber();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ void CCalcEngine::DisplayNum(void)
|
||||||
// called.
|
// called.
|
||||||
//
|
//
|
||||||
if (m_bRecord || gldPrevious.value != m_currentVal || gldPrevious.precision != m_precision || gldPrevious.radix != m_radix || gldPrevious.nFE != (int)m_nFE
|
if (m_bRecord || gldPrevious.value != m_currentVal || gldPrevious.precision != m_precision || gldPrevious.radix != m_radix || gldPrevious.nFE != (int)m_nFE
|
||||||
|| gldPrevious.bUseSep != true || gldPrevious.numwidth != m_numwidth || gldPrevious.fIntMath != m_fIntegerMode || gldPrevious.bRecord != m_bRecord)
|
|| !gldPrevious.bUseSep || gldPrevious.numwidth != m_numwidth || gldPrevious.fIntMath != m_fIntegerMode || gldPrevious.bRecord != m_bRecord)
|
||||||
{
|
{
|
||||||
gldPrevious.precision = m_precision;
|
gldPrevious.precision = m_precision;
|
||||||
gldPrevious.radix = m_radix;
|
gldPrevious.radix = m_radix;
|
||||||
|
|
|
@ -42,7 +42,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = rat ^ m_chopNumbers[m_numwidth];
|
result = rat ^ GetChopNumber();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_NAND:
|
case IDC_NAND:
|
||||||
result = (result & rhs) ^ m_chopNumbers[m_numwidth];
|
result = (result & rhs) ^ GetChopNumber();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_NOR:
|
case IDC_NOR:
|
||||||
result = (result | rhs) ^ m_chopNumbers[m_numwidth];
|
result = (result | rhs) ^ GetChopNumber();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_RSHF:
|
case IDC_RSHF:
|
||||||
|
@ -53,10 +53,10 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
|
||||||
{
|
{
|
||||||
result = Integer(result);
|
result = Integer(result);
|
||||||
|
|
||||||
auto tempRat = m_chopNumbers[m_numwidth] >> holdVal;
|
auto tempRat = GetChopNumber() >> holdVal;
|
||||||
tempRat = Integer(tempRat);
|
tempRat = Integer(tempRat);
|
||||||
|
|
||||||
result |= tempRat ^ m_chopNumbers[m_numwidth];
|
result |= tempRat ^ GetChopNumber();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
|
||||||
|
|
||||||
if (fMsb)
|
if (fMsb)
|
||||||
{
|
{
|
||||||
result = (rhs ^ m_chopNumbers[m_numwidth]) + 1;
|
result = (rhs ^ GetChopNumber()) + 1;
|
||||||
|
|
||||||
iNumeratorSign = -1;
|
iNumeratorSign = -1;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
|
||||||
|
|
||||||
if (fMsb)
|
if (fMsb)
|
||||||
{
|
{
|
||||||
temp = (temp ^ m_chopNumbers[m_numwidth]) + 1;
|
temp = (temp ^ GetChopNumber()) + 1;
|
||||||
|
|
||||||
iDenominatorSign = -1;
|
iDenominatorSign = -1;
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,8 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa
|
||||||
result = Root(rhs, result);
|
result = Root(rhs, result);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IDC_LOGBASEX:
|
case IDC_LOGBASEY:
|
||||||
result = (Log(result) / Log(rhs));
|
result = (Log(rhs) / Log(result));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ using namespace std;
|
||||||
|
|
||||||
// To be called when either the radix or num width changes. You can use -1 in either of these values to mean
|
// To be called when either the radix or num width changes. You can use -1 in either of these values to mean
|
||||||
// dont change that.
|
// dont change that.
|
||||||
void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth)
|
void CCalcEngine::SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidth)
|
||||||
{
|
{
|
||||||
// When in integer mode, the number is represented in 2's complement form. When a bit width is changing, we can
|
// When in integer mode, the number is represented in 2's complement form. When a bit width is changing, we can
|
||||||
// change the number representation back to sign, abs num form in ratpak. Soon when display sees this, it will
|
// change the number representation back to sign, abs num form in ratpak. Soon when display sees this, it will
|
||||||
|
@ -24,19 +24,19 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwid
|
||||||
if (fMsb)
|
if (fMsb)
|
||||||
{
|
{
|
||||||
// If high bit is set, then get the decimal number in -ve 2'scompl form.
|
// If high bit is set, then get the decimal number in -ve 2'scompl form.
|
||||||
auto tempResult = m_currentVal ^ m_chopNumbers[m_numwidth];
|
auto tempResult = m_currentVal ^ GetChopNumber();
|
||||||
|
|
||||||
m_currentVal = -(tempResult + 1);
|
m_currentVal = -(tempResult + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (radixtype >= HEX_RADIX && radixtype <= BIN_RADIX)
|
if (radixtype >= RadixType::Hex && radixtype <= RadixType::Binary)
|
||||||
{
|
{
|
||||||
m_radix = NRadixFromRadixType(radixtype);
|
m_radix = NRadixFromRadixType(radixtype);
|
||||||
// radixtype is not even saved
|
// radixtype is not even saved
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numwidth >= QWORD_WIDTH && numwidth <= BYTE_WIDTH)
|
if (numwidth >= NUM_WIDTH::QWORD_WIDTH && numwidth <= NUM_WIDTH::BYTE_WIDTH)
|
||||||
{
|
{
|
||||||
m_numwidth = numwidth;
|
m_numwidth = numwidth;
|
||||||
m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(numwidth);
|
m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(numwidth);
|
||||||
|
@ -50,29 +50,36 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwid
|
||||||
DisplayNum();
|
DisplayNum();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/)
|
int32_t CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth)
|
||||||
{
|
{
|
||||||
static constexpr int nBitMax[] = { 64, 32, 16, 8 };
|
switch (numwidth)
|
||||||
int32_t wmax = nBitMax[0];
|
|
||||||
|
|
||||||
if (m_numwidth >= 0 && (size_t)m_numwidth < size(nBitMax))
|
|
||||||
{
|
{
|
||||||
wmax = nBitMax[m_numwidth];
|
case NUM_WIDTH::DWORD_WIDTH:
|
||||||
|
return 32;
|
||||||
|
case NUM_WIDTH::WORD_WIDTH:
|
||||||
|
return 16;
|
||||||
|
case NUM_WIDTH::BYTE_WIDTH:
|
||||||
|
return 8;
|
||||||
|
case NUM_WIDTH::QWORD_WIDTH:
|
||||||
|
default:
|
||||||
|
return 64;
|
||||||
}
|
}
|
||||||
return wmax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype)
|
uint32_t CCalcEngine::NRadixFromRadixType(RadixType radixtype)
|
||||||
{
|
{
|
||||||
static constexpr uint32_t rgnRadish[4] = { 16, 10, 8, 2 }; /* Number bases in the same order as radixtype */
|
switch (radixtype)
|
||||||
uint32_t radix = 10;
|
|
||||||
|
|
||||||
// convert special bases into symbolic values
|
|
||||||
if (radixtype >= 0 && (size_t)radixtype < size(rgnRadish))
|
|
||||||
{
|
{
|
||||||
radix = rgnRadish[radixtype];
|
case RadixType::Hex:
|
||||||
|
return 16;
|
||||||
|
case RadixType::Octal:
|
||||||
|
return 8;
|
||||||
|
case RadixType::Binary:
|
||||||
|
return 2;
|
||||||
|
case RadixType::Decimal:
|
||||||
|
default:
|
||||||
|
return 10;
|
||||||
}
|
}
|
||||||
return radix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggles a given bit into the number representation. returns true if it changed it actually.
|
// Toggles a given bit into the number representation. returns true if it changed it actually.
|
||||||
|
@ -141,7 +148,7 @@ void CCalcEngine::UpdateMaxIntDigits()
|
||||||
// if in integer mode you still have to honor the max digits you can enter based on bit width
|
// if in integer mode you still have to honor the max digits you can enter based on bit width
|
||||||
if (m_fIntegerMode)
|
if (m_fIntegerMode)
|
||||||
{
|
{
|
||||||
m_cIntDigitsSav = static_cast<int>(m_maxDecimalValueStrings[m_numwidth].length()) - 1;
|
m_cIntDigitsSav = static_cast<int>(GetMaxDecimalValueString().length()) - 1;
|
||||||
// This is the max digits you can enter a decimal in fixed width mode aka integer mode -1. The last digit
|
// This is the max digits you can enter a decimal in fixed width mode aka integer mode -1. The last digit
|
||||||
// has to be checked separately
|
// has to be checked separately
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
add_library(CalcManager
|
|
||||||
CalculatorHistory.cpp
|
|
||||||
CalculatorManager.cpp
|
|
||||||
ExpressionCommand.cpp
|
|
||||||
pch.cpp
|
|
||||||
UnitConverter.cpp
|
|
||||||
)
|
|
||||||
target_include_directories(CalcManager PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
|
|
||||||
add_subdirectory(Ratpack)
|
|
||||||
add_subdirectory(CEngine)
|
|
|
@ -132,29 +132,9 @@
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup />
|
<PropertyGroup />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup>
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
<GenerateManifest>false</GenerateManifest>
|
||||||
|
<GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
|
|
|
@ -41,21 +41,13 @@ unsigned int CalculatorHistory::AddToHistory(
|
||||||
_In_ shared_ptr<vector<shared_ptr<IExpressionCommand>>> const& commands,
|
_In_ shared_ptr<vector<shared_ptr<IExpressionCommand>>> const& commands,
|
||||||
wstring_view result)
|
wstring_view result)
|
||||||
{
|
{
|
||||||
unsigned int addedIndex;
|
|
||||||
shared_ptr<HISTORYITEM> spHistoryItem = make_shared<HISTORYITEM>();
|
shared_ptr<HISTORYITEM> spHistoryItem = make_shared<HISTORYITEM>();
|
||||||
|
|
||||||
spHistoryItem->historyItemVector.spTokens = tokens;
|
spHistoryItem->historyItemVector.spTokens = tokens;
|
||||||
spHistoryItem->historyItemVector.spCommands = commands;
|
spHistoryItem->historyItemVector.spCommands = commands;
|
||||||
|
spHistoryItem->historyItemVector.expression = GetGeneratedExpression(*tokens);
|
||||||
// to be changed when pszexp is back
|
|
||||||
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';
|
|
||||||
spHistoryItem->historyItemVector.result = wstring(result);
|
spHistoryItem->historyItemVector.result = wstring(result);
|
||||||
addedIndex = AddItem(spHistoryItem);
|
return AddItem(spHistoryItem);
|
||||||
|
|
||||||
return addedIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const& spHistoryItem)
|
unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const& spHistoryItem)
|
||||||
|
@ -66,19 +58,18 @@ unsigned int CalculatorHistory::AddItem(_In_ shared_ptr<HISTORYITEM> const& spHi
|
||||||
}
|
}
|
||||||
|
|
||||||
m_historyItems.push_back(spHistoryItem);
|
m_historyItems.push_back(spHistoryItem);
|
||||||
unsigned int lastIndex = static_cast<unsigned>(m_historyItems.size() - 1);
|
return static_cast<unsigned>(m_historyItems.size() - 1);
|
||||||
return lastIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalculatorHistory::RemoveItem(unsigned int uIdx)
|
bool CalculatorHistory::RemoveItem(unsigned int uIdx)
|
||||||
{
|
{
|
||||||
if (uIdx > m_historyItems.size() - 1)
|
if (uIdx < m_historyItems.size())
|
||||||
{
|
{
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_historyItems.erase(m_historyItems.begin() + uIdx);
|
m_historyItems.erase(m_historyItems.begin() + uIdx);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<shared_ptr<HISTORYITEM>> const& CalculatorHistory::GetHistory()
|
vector<shared_ptr<HISTORYITEM>> const& CalculatorHistory::GetHistory()
|
||||||
|
|
|
@ -7,12 +7,6 @@
|
||||||
|
|
||||||
namespace CalculationManager
|
namespace CalculationManager
|
||||||
{
|
{
|
||||||
enum CALCULATOR_MODE
|
|
||||||
{
|
|
||||||
CM_STD = 0,
|
|
||||||
CM_SCI,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HISTORYITEMVECTOR
|
struct HISTORYITEMVECTOR
|
||||||
{
|
{
|
||||||
std::shared_ptr<std::vector<std::pair<std::wstring, int>>> spTokens;
|
std::shared_ptr<std::vector<std::pair<std::wstring, int>>> spTokens;
|
||||||
|
|
|
@ -10,16 +10,11 @@ using namespace std;
|
||||||
using namespace CalcEngine;
|
using namespace CalcEngine;
|
||||||
|
|
||||||
static constexpr size_t MAX_HISTORY_ITEMS = 20;
|
static constexpr size_t MAX_HISTORY_ITEMS = 20;
|
||||||
static constexpr size_t SERIALIZED_NUMBER_MINSIZE = 3;
|
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#define __pragma(x)
|
#define __pragma(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Converts Memory Command enum value to unsigned char,
|
|
||||||
// while ignoring Warning C4309: 'conversion' : truncation of constant value
|
|
||||||
#define MEMORY_COMMAND_TO_UNSIGNED_CHAR(c) __pragma(warning(push)) __pragma(warning(disable : 4309)) static_cast<unsigned char>(c) __pragma(warning(pop))
|
|
||||||
|
|
||||||
namespace CalculationManager
|
namespace CalculationManager
|
||||||
{
|
{
|
||||||
CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider)
|
CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider)
|
||||||
|
@ -30,9 +25,9 @@ namespace CalculationManager
|
||||||
, m_persistedPrimaryValue()
|
, m_persistedPrimaryValue()
|
||||||
, m_isExponentialFormat(false)
|
, m_isExponentialFormat(false)
|
||||||
, m_currentDegreeMode(Command::CommandNULL)
|
, m_currentDegreeMode(Command::CommandNULL)
|
||||||
, m_savedDegreeMode(Command::CommandDEG)
|
|
||||||
, m_pStdHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
|
, m_pStdHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
|
||||||
, m_pSciHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
|
, m_pSciHistory(new CalculatorHistory(MAX_HISTORY_ITEMS))
|
||||||
|
, m_pHistory(nullptr)
|
||||||
{
|
{
|
||||||
CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider);
|
CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +126,6 @@ namespace CalculationManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void CalculatorManager::Reset(bool clearMemory /* = true*/)
|
void CalculatorManager::Reset(bool clearMemory /* = true*/)
|
||||||
{
|
{
|
||||||
m_savedCommands.clear();
|
|
||||||
SetStandardMode();
|
SetStandardMode();
|
||||||
|
|
||||||
if (m_scientificCalculatorEngine)
|
if (m_scientificCalculatorEngine)
|
||||||
|
@ -238,13 +232,6 @@ namespace CalculationManager
|
||||||
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(command));
|
m_currentCalculatorEngine->ProcessCommand(static_cast<OpCode>(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_savedCommands.clear(); // Clear the previous command history
|
|
||||||
|
|
||||||
if (command != Command::CommandEQU && command != Command::CommandCLEAR)
|
|
||||||
{
|
|
||||||
m_savedCommands.push_back(MapCommandForSerialize(command));
|
|
||||||
}
|
|
||||||
m_savedDegreeMode = m_currentDegreeMode;
|
|
||||||
InputChanged();
|
InputChanged();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -254,11 +241,6 @@ namespace CalculationManager
|
||||||
m_currentDegreeMode = command;
|
m_currentDegreeMode = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command != Command::CommandFE)
|
|
||||||
{
|
|
||||||
m_savedCommands.push_back(MapCommandForSerialize(command)); // Save the commands in the m_savedCommands
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
case Command::CommandASIN:
|
case Command::CommandASIN:
|
||||||
|
@ -324,37 +306,6 @@ namespace CalculationManager
|
||||||
InputChanged();
|
InputChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert Command to unsigned char.
|
|
||||||
/// Since some Commands are higher than 255, they are saved after subtracting 255
|
|
||||||
/// The smallest Command is CommandSIGN = 80, thus, subtracted value does not overlap with other values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="command">Enum Command</command>
|
|
||||||
unsigned char CalculatorManager::MapCommandForSerialize(Command command)
|
|
||||||
{
|
|
||||||
unsigned int commandToSave = static_cast<unsigned int>(command);
|
|
||||||
if (commandToSave > UCHAR_MAX)
|
|
||||||
{
|
|
||||||
commandToSave -= UCHAR_MAX;
|
|
||||||
}
|
|
||||||
return static_cast<unsigned char>(commandToSave);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert Command to unsigned int
|
|
||||||
/// The command that is smaller than 80, CommandSIGN, can be converted back to original value by adding 255.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="command">unsigned char value represent the saved command</command>
|
|
||||||
unsigned int CalculatorManager::MapCommandForDeSerialize(unsigned char command)
|
|
||||||
{
|
|
||||||
unsigned int commandToLoad = command;
|
|
||||||
if (command < static_cast<unsigned int>(Command::CommandSIGN))
|
|
||||||
{
|
|
||||||
commandToLoad += UCHAR_MAX;
|
|
||||||
}
|
|
||||||
return commandToLoad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load the persisted value that is saved in memory of CalcEngine
|
/// Load the persisted value that is saved in memory of CalcEngine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -371,8 +322,6 @@ namespace CalculationManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void CalculatorManager::MemorizeNumber()
|
void CalculatorManager::MemorizeNumber()
|
||||||
{
|
{
|
||||||
m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizeNumber));
|
|
||||||
|
|
||||||
if (m_currentCalculatorEngine->FInErrorState())
|
if (m_currentCalculatorEngine->FInErrorState())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -400,8 +349,6 @@ namespace CalculationManager
|
||||||
/// <param name="indexOfMemory">Index of the target memory</param>
|
/// <param name="indexOfMemory">Index of the target memory</param>
|
||||||
void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory)
|
void CalculatorManager::MemorizedNumberLoad(_In_ unsigned int indexOfMemory)
|
||||||
{
|
{
|
||||||
SaveMemoryCommand(MemoryCommand::MemorizedNumberLoad, indexOfMemory);
|
|
||||||
|
|
||||||
if (m_currentCalculatorEngine->FInErrorState())
|
if (m_currentCalculatorEngine->FInErrorState())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -420,8 +367,6 @@ namespace CalculationManager
|
||||||
/// <param name="indexOfMemory">Index of the target memory</param>
|
/// <param name="indexOfMemory">Index of the target memory</param>
|
||||||
void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory)
|
void CalculatorManager::MemorizedNumberAdd(_In_ unsigned int indexOfMemory)
|
||||||
{
|
{
|
||||||
SaveMemoryCommand(MemoryCommand::MemorizedNumberAdd, indexOfMemory);
|
|
||||||
|
|
||||||
if (m_currentCalculatorEngine->FInErrorState())
|
if (m_currentCalculatorEngine->FInErrorState())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -448,7 +393,6 @@ namespace CalculationManager
|
||||||
{
|
{
|
||||||
if (indexOfMemory < m_memorizedNumbers.size())
|
if (indexOfMemory < m_memorizedNumbers.size())
|
||||||
{
|
{
|
||||||
SaveMemoryCommand(MemoryCommand::MemorizedNumberClear, indexOfMemory);
|
|
||||||
m_memorizedNumbers.erase(m_memorizedNumbers.begin() + indexOfMemory);
|
m_memorizedNumbers.erase(m_memorizedNumbers.begin() + indexOfMemory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,8 +405,6 @@ namespace CalculationManager
|
||||||
/// <param name="indexOfMemory">Index of the target memory</param>
|
/// <param name="indexOfMemory">Index of the target memory</param>
|
||||||
void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory)
|
void CalculatorManager::MemorizedNumberSubtract(_In_ unsigned int indexOfMemory)
|
||||||
{
|
{
|
||||||
SaveMemoryCommand(MemoryCommand::MemorizedNumberSubtract, indexOfMemory);
|
|
||||||
|
|
||||||
if (m_currentCalculatorEngine->FInErrorState())
|
if (m_currentCalculatorEngine->FInErrorState())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -494,7 +436,6 @@ namespace CalculationManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void CalculatorManager::MemorizedNumberClearAll()
|
void CalculatorManager::MemorizedNumberClearAll()
|
||||||
{
|
{
|
||||||
m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(MemoryCommand::MemorizedNumberClearAll));
|
|
||||||
m_memorizedNumbers.clear();
|
m_memorizedNumbers.clear();
|
||||||
|
|
||||||
m_currentCalculatorEngine->ProcessCommand(IDC_MCLEAR);
|
m_currentCalculatorEngine->ProcessCommand(IDC_MCLEAR);
|
||||||
|
@ -536,24 +477,14 @@ namespace CalculationManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalculatorManager::SaveMemoryCommand(_In_ MemoryCommand command, _In_ unsigned int indexOfMemory)
|
|
||||||
{
|
|
||||||
m_savedCommands.push_back(MEMORY_COMMAND_TO_UNSIGNED_CHAR(command));
|
|
||||||
if (indexOfMemory > UCHAR_MAX)
|
|
||||||
{
|
|
||||||
throw invalid_argument("Unexpected value. IndexOfMemory is bigger than the biggest unsigned char");
|
|
||||||
}
|
|
||||||
m_savedCommands.push_back(static_cast<unsigned char>(indexOfMemory));
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems()
|
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems()
|
||||||
{
|
{
|
||||||
return m_pHistory->GetHistory();
|
return m_pHistory->GetHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems(_In_ CALCULATOR_MODE mode)
|
vector<shared_ptr<HISTORYITEM>> const& CalculatorManager::GetHistoryItems(_In_ CalculatorMode mode)
|
||||||
{
|
{
|
||||||
return (mode == CM_STD) ? m_pStdHistory->GetHistory() : m_pSciHistory->GetHistory();
|
return (mode == CalculatorMode::Standard) ? m_pStdHistory->GetHistory() : m_pSciHistory->GetHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<HISTORYITEM> const& CalculatorManager::GetHistoryItem(_In_ unsigned int uIdx)
|
shared_ptr<HISTORYITEM> const& CalculatorManager::GetHistoryItem(_In_ unsigned int uIdx)
|
||||||
|
@ -576,20 +507,20 @@ namespace CalculationManager
|
||||||
m_pHistory->ClearHistory();
|
m_pHistory->ClearHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalculatorManager::SetRadix(RADIX_TYPE iRadixType)
|
void CalculatorManager::SetRadix(RadixType iRadixType)
|
||||||
{
|
{
|
||||||
switch (iRadixType)
|
switch (iRadixType)
|
||||||
{
|
{
|
||||||
case RADIX_TYPE::HEX_RADIX:
|
case RadixType::Hex:
|
||||||
m_currentCalculatorEngine->ProcessCommand(IDC_HEX);
|
m_currentCalculatorEngine->ProcessCommand(IDC_HEX);
|
||||||
break;
|
break;
|
||||||
case RADIX_TYPE::DEC_RADIX:
|
case RadixType::Decimal:
|
||||||
m_currentCalculatorEngine->ProcessCommand(IDC_DEC);
|
m_currentCalculatorEngine->ProcessCommand(IDC_DEC);
|
||||||
break;
|
break;
|
||||||
case RADIX_TYPE::OCT_RADIX:
|
case RadixType::Octal:
|
||||||
m_currentCalculatorEngine->ProcessCommand(IDC_OCT);
|
m_currentCalculatorEngine->ProcessCommand(IDC_OCT);
|
||||||
break;
|
break;
|
||||||
case RADIX_TYPE::BIN_RADIX:
|
case RadixType::Binary:
|
||||||
m_currentCalculatorEngine->ProcessCommand(IDC_BIN);
|
m_currentCalculatorEngine->ProcessCommand(IDC_BIN);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -603,7 +534,7 @@ namespace CalculationManager
|
||||||
vector<wstring> resultVector;
|
vector<wstring> resultVector;
|
||||||
for (auto const& memoryItem : m_memorizedNumbers)
|
for (auto const& memoryItem : m_memorizedNumbers)
|
||||||
{
|
{
|
||||||
int radix = m_currentCalculatorEngine->GetCurrentRadix();
|
auto radix = m_currentCalculatorEngine->GetCurrentRadix();
|
||||||
wstring stringValue = m_currentCalculatorEngine->GetStringForDisplay(memoryItem, radix);
|
wstring stringValue = m_currentCalculatorEngine->GetStringForDisplay(memoryItem, radix);
|
||||||
|
|
||||||
if (!stringValue.empty())
|
if (!stringValue.empty())
|
||||||
|
@ -623,30 +554,6 @@ namespace CalculationManager
|
||||||
return m_currentDegreeMode;
|
return m_currentDegreeMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalculatorManager::SetHistory(_In_ CALCULATOR_MODE eMode, _In_ vector<shared_ptr<HISTORYITEM>> const& history)
|
|
||||||
{
|
|
||||||
CalculatorHistory* pHistory = nullptr;
|
|
||||||
|
|
||||||
switch (eMode)
|
|
||||||
{
|
|
||||||
case CM_STD:
|
|
||||||
pHistory = m_pStdHistory.get();
|
|
||||||
break;
|
|
||||||
case CM_SCI:
|
|
||||||
pHistory = m_pSciHistory.get();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pHistory)
|
|
||||||
{
|
|
||||||
pHistory->ClearHistory();
|
|
||||||
for (auto const& historyItem : history)
|
|
||||||
{
|
|
||||||
pHistory->AddItem(historyItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring CalculatorManager::GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix)
|
wstring CalculatorManager::GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix)
|
||||||
{
|
{
|
||||||
return m_currentCalculatorEngine ? m_currentCalculatorEngine->GetCurrentResultForRadix(radix, precision, groupDigitsPerRadix) : L"";
|
return m_currentCalculatorEngine ? m_currentCalculatorEngine->GetCurrentResultForRadix(radix, precision, groupDigitsPerRadix) : L"";
|
||||||
|
@ -669,7 +576,7 @@ namespace CalculationManager
|
||||||
|
|
||||||
bool CalculatorManager::IsEngineRecording()
|
bool CalculatorManager::IsEngineRecording()
|
||||||
{
|
{
|
||||||
return m_currentCalculatorEngine->FInRecordingState() ? true : false;
|
return m_currentCalculatorEngine->FInRecordingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalculatorManager::IsInputEmpty()
|
bool CalculatorManager::IsInputEmpty()
|
||||||
|
|
|
@ -15,9 +15,8 @@ namespace CalculationManager
|
||||||
|
|
||||||
enum class CalculatorMode
|
enum class CalculatorMode
|
||||||
{
|
{
|
||||||
StandardMode,
|
Standard = 0,
|
||||||
ScientificMode,
|
Scientific,
|
||||||
ProgrammerMode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CalculatorPrecision
|
enum class CalculatorPrecision
|
||||||
|
@ -45,6 +44,7 @@ namespace CalculationManager
|
||||||
class CalculatorManager final : public ICalcDisplay
|
class CalculatorManager final : public ICalcDisplay
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
static const unsigned int m_maximumMemorySize = 100;
|
||||||
ICalcDisplay* const m_displayCallback;
|
ICalcDisplay* const m_displayCallback;
|
||||||
CCalcEngine* m_currentCalculatorEngine;
|
CCalcEngine* m_currentCalculatorEngine;
|
||||||
std::unique_ptr<CCalcEngine> m_scientificCalculatorEngine;
|
std::unique_ptr<CCalcEngine> m_scientificCalculatorEngine;
|
||||||
|
@ -55,21 +55,8 @@ namespace CalculationManager
|
||||||
|
|
||||||
std::vector<CalcEngine::Rational> m_memorizedNumbers;
|
std::vector<CalcEngine::Rational> m_memorizedNumbers;
|
||||||
CalcEngine::Rational m_persistedPrimaryValue;
|
CalcEngine::Rational m_persistedPrimaryValue;
|
||||||
|
|
||||||
bool m_isExponentialFormat;
|
bool m_isExponentialFormat;
|
||||||
|
|
||||||
static const unsigned int m_maximumMemorySize = 100;
|
|
||||||
|
|
||||||
// For persistence
|
|
||||||
std::vector<unsigned char> m_savedCommands;
|
|
||||||
std::vector<long> m_savedPrimaryValue;
|
|
||||||
std::vector<long> m_currentSerializedMemory;
|
|
||||||
Command m_currentDegreeMode;
|
Command m_currentDegreeMode;
|
||||||
Command m_savedDegreeMode;
|
|
||||||
unsigned char MapCommandForSerialize(Command command);
|
|
||||||
unsigned int MapCommandForDeSerialize(unsigned char command);
|
|
||||||
|
|
||||||
void SaveMemoryCommand(_In_ MemoryCommand command, _In_ unsigned int indexOfMemory);
|
|
||||||
|
|
||||||
void MemorizedNumberSelect(_In_ unsigned int);
|
void MemorizedNumberSelect(_In_ unsigned int);
|
||||||
void MemorizedNumberChanged(_In_ unsigned int);
|
void MemorizedNumberChanged(_In_ unsigned int);
|
||||||
|
@ -113,11 +100,7 @@ namespace CalculationManager
|
||||||
|
|
||||||
bool IsEngineRecording();
|
bool IsEngineRecording();
|
||||||
bool IsInputEmpty();
|
bool IsInputEmpty();
|
||||||
const std::vector<unsigned char>& GetSavedCommands() const
|
void SetRadix(RadixType iRadixType);
|
||||||
{
|
|
||||||
return m_savedCommands;
|
|
||||||
}
|
|
||||||
void SetRadix(RADIX_TYPE iRadixType);
|
|
||||||
void SetMemorizedNumbersString();
|
void SetMemorizedNumbersString();
|
||||||
std::wstring GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
|
std::wstring GetResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
|
||||||
void SetPrecision(int32_t precision);
|
void SetPrecision(int32_t precision);
|
||||||
|
@ -125,7 +108,7 @@ namespace CalculationManager
|
||||||
wchar_t DecimalSeparator();
|
wchar_t DecimalSeparator();
|
||||||
|
|
||||||
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistoryItems();
|
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistoryItems();
|
||||||
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistoryItems(_In_ CalculationManager::CALCULATOR_MODE mode);
|
std::vector<std::shared_ptr<HISTORYITEM>> const& GetHistoryItems(_In_ CalculatorMode mode);
|
||||||
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(_In_ unsigned int uIdx);
|
std::shared_ptr<HISTORYITEM> const& GetHistoryItem(_In_ unsigned int uIdx);
|
||||||
bool RemoveHistoryItem(_In_ unsigned int uIdx);
|
bool RemoveHistoryItem(_In_ unsigned int uIdx);
|
||||||
void ClearHistory();
|
void ClearHistory();
|
||||||
|
@ -134,7 +117,6 @@ namespace CalculationManager
|
||||||
return m_pHistory->MaxHistorySize();
|
return m_pHistory->MaxHistorySize();
|
||||||
}
|
}
|
||||||
CalculationManager::Command GetCurrentDegreeMode();
|
CalculationManager::Command GetCurrentDegreeMode();
|
||||||
void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector<std::shared_ptr<HISTORYITEM>> const& history);
|
|
||||||
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);
|
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
156
src/CalcManager/CalculatorVector.h
Normal file
156
src/CalcManager/CalculatorVector.h
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "winerror_cross_platform.h"
|
||||||
|
#include "Ratpack/CalcErr.h"
|
||||||
|
#include <stdexcept> // for std::out_of_range
|
||||||
|
#include "sal_cross_platform.h" // for SAL
|
||||||
|
|
||||||
|
template <typename TType>
|
||||||
|
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<unsigned>(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<std::wstring, int> 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<TType> m_vector;
|
||||||
|
};
|
|
@ -69,10 +69,6 @@ namespace CalculationManager
|
||||||
|
|
||||||
CommandNULL = 0,
|
CommandNULL = 0,
|
||||||
|
|
||||||
// No new command should not be added before CommandSign, 80
|
|
||||||
// If it is needed, the following two functions need to be revised too.
|
|
||||||
// CalculatorManager::MapCommandForSerialize(Command command);
|
|
||||||
// CalculatorManager::MapCommandForDeSerialize(unsigned char command);
|
|
||||||
CommandSIGN = 80,
|
CommandSIGN = 80,
|
||||||
CommandCLEAR = 81,
|
CommandCLEAR = 81,
|
||||||
CommandCENTR = 82,
|
CommandCENTR = 82,
|
||||||
|
@ -172,7 +168,7 @@ namespace CalculationManager
|
||||||
CommandCeil = 415,
|
CommandCeil = 415,
|
||||||
CommandROLC = 416,
|
CommandROLC = 416,
|
||||||
CommandRORC = 417,
|
CommandRORC = 417,
|
||||||
CommandLogBaseX = 500,
|
CommandLogBaseY = 500,
|
||||||
CommandNand = 501,
|
CommandNand = 501,
|
||||||
CommandNor = 502,
|
CommandNor = 502,
|
||||||
|
|
||||||
|
|
|
@ -277,7 +277,7 @@ wstring COpndCommand::GetString(uint32_t radix, int32_t precision)
|
||||||
{
|
{
|
||||||
if (m_fInitialized)
|
if (m_fInitialized)
|
||||||
{
|
{
|
||||||
return m_value.ToString(radix, eNUMOBJ_FMT::FMT_FLOAT, precision);
|
return m_value.ToString(radix, NumberFormat::Float, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
return wstring{};
|
return wstring{};
|
||||||
|
|
|
@ -166,7 +166,7 @@
|
||||||
#define IDC_LASTCONTROL IDC_CEIL
|
#define IDC_LASTCONTROL IDC_CEIL
|
||||||
|
|
||||||
#define IDC_BINARYEXTENDEDFIRST 500
|
#define IDC_BINARYEXTENDEDFIRST 500
|
||||||
#define IDC_LOGBASEX 500 // logx(y)
|
#define IDC_LOGBASEY 500 // logy(x)
|
||||||
#define IDC_NAND 501 // Nand
|
#define IDC_NAND 501 // Nand
|
||||||
#define IDC_NOR 502 // Nor
|
#define IDC_NOR 502 // Nor
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,13 @@
|
||||||
// The real exports follows later
|
// The real exports follows later
|
||||||
|
|
||||||
// This is expected to be in same order as IDM_QWORD, IDM_DWORD etc.
|
// This is expected to be in same order as IDM_QWORD, IDM_DWORD etc.
|
||||||
enum eNUM_WIDTH
|
enum class NUM_WIDTH
|
||||||
{
|
{
|
||||||
QWORD_WIDTH, // Number width of 64 bits mode (default)
|
QWORD_WIDTH, // Number width of 64 bits mode (default)
|
||||||
DWORD_WIDTH, // Number width of 32 bits mode
|
DWORD_WIDTH, // Number width of 32 bits mode
|
||||||
WORD_WIDTH, // Number width of 16 bits mode
|
WORD_WIDTH, // Number width of 16 bits mode
|
||||||
BYTE_WIDTH // Number width of 16 bits mode
|
BYTE_WIDTH // Number width of 16 bits mode
|
||||||
};
|
};
|
||||||
typedef enum eNUM_WIDTH NUM_WIDTH;
|
|
||||||
static constexpr size_t NUM_WIDTH_LENGTH = 4;
|
static constexpr size_t NUM_WIDTH_LENGTH = 4;
|
||||||
|
|
||||||
namespace CalculationManager
|
namespace CalculationManager
|
||||||
|
@ -78,7 +77,7 @@ public:
|
||||||
}
|
}
|
||||||
void SettingsChanged();
|
void SettingsChanged();
|
||||||
bool IsCurrentTooBigForTrig();
|
bool IsCurrentTooBigForTrig();
|
||||||
int GetCurrentRadix();
|
uint32_t GetCurrentRadix();
|
||||||
std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
|
std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
|
||||||
void ChangePrecision(int32_t precision)
|
void ChangePrecision(int32_t precision)
|
||||||
{
|
{
|
||||||
|
@ -106,7 +105,7 @@ public:
|
||||||
{
|
{
|
||||||
return GetString(IdStrFromCmdId(nOpCode));
|
return GetString(IdStrFromCmdId(nOpCode));
|
||||||
}
|
}
|
||||||
static std::wstring_view OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype);
|
static std::wstring_view OpCodeToUnaryString(int nOpCode, bool fInv, AngleType angletype);
|
||||||
static std::wstring_view OpCodeToBinaryString(int nOpCode, bool isIntegerMode);
|
static std::wstring_view OpCodeToBinaryString(int nOpCode, bool isIntegerMode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -117,11 +116,11 @@ private:
|
||||||
int m_nOpCode; /* ID value of operation. */
|
int m_nOpCode; /* ID value of operation. */
|
||||||
int m_nPrevOpCode; // opcode which computed the number in m_currentVal. 0 if it is already bracketed or plain number or
|
int m_nPrevOpCode; // opcode which computed the number in m_currentVal. 0 if it is already bracketed or plain number or
|
||||||
// if it hasn't yet been computed
|
// if it hasn't yet been computed
|
||||||
bool m_bChangeOp; /* Flag for changing operation. */
|
bool m_bChangeOp; // Flag for changing operation
|
||||||
bool m_bRecord; // Global mode: recording or displaying
|
bool m_bRecord; // Global mode: recording or displaying
|
||||||
bool m_bSetCalcState; // Flag for setting the engine result state
|
bool m_bSetCalcState; // Flag for setting the engine result state
|
||||||
CalcEngine::CalcInput m_input; // Global calc input object for decimal strings
|
CalcEngine::CalcInput m_input; // Global calc input object for decimal strings
|
||||||
eNUMOBJ_FMT m_nFE; /* Scientific notation conversion flag. */
|
NumberFormat m_nFE; // Scientific notation conversion flag
|
||||||
CalcEngine::Rational m_maxTrigonometricNum;
|
CalcEngine::Rational m_maxTrigonometricNum;
|
||||||
std::unique_ptr<CalcEngine::Rational> m_memoryValue; // Current memory value.
|
std::unique_ptr<CalcEngine::Rational> m_memoryValue; // Current memory value.
|
||||||
|
|
||||||
|
@ -148,7 +147,7 @@ private:
|
||||||
std::array<int, MAXPRECDEPTH> m_nPrecOp; /* Holding array for precedence operations. */
|
std::array<int, MAXPRECDEPTH> m_nPrecOp; /* Holding array for precedence operations. */
|
||||||
size_t m_precedenceOpCount; /* Current number of precedence ops in holding. */
|
size_t m_precedenceOpCount; /* Current number of precedence ops in holding. */
|
||||||
int m_nLastCom; // Last command entered.
|
int m_nLastCom; // Last command entered.
|
||||||
ANGLE_TYPE m_angletype; // Current Angle type when in dec mode. one of deg, rad or grad
|
AngleType m_angletype; // Current Angle type when in dec mode. one of deg, rad or grad
|
||||||
NUM_WIDTH m_numwidth; // one of qword, dword, word or byte mode.
|
NUM_WIDTH m_numwidth; // one of qword, dword, word or byte mode.
|
||||||
int32_t m_dwWordBitWidth; // # of bits in currently selected word size
|
int32_t m_dwWordBitWidth; // # of bits in currently selected word size
|
||||||
|
|
||||||
|
@ -179,15 +178,17 @@ private:
|
||||||
CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat);
|
CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat);
|
||||||
CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op);
|
CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op);
|
||||||
CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs);
|
CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs);
|
||||||
void SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth);
|
void SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidth);
|
||||||
int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth);
|
int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth);
|
||||||
uint32_t NRadixFromRadixType(RADIX_TYPE radixtype);
|
uint32_t NRadixFromRadixType(RadixType radixtype);
|
||||||
double GenerateRandomNumber();
|
double GenerateRandomNumber();
|
||||||
|
|
||||||
bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno);
|
bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno);
|
||||||
void CheckAndAddLastBinOpToHistory(bool addToHistory = true);
|
void CheckAndAddLastBinOpToHistory(bool addToHistory = true);
|
||||||
|
|
||||||
void InitChopNumbers();
|
void InitChopNumbers();
|
||||||
|
CalcEngine::Rational GetChopNumber() const;
|
||||||
|
std::wstring GetMaxDecimalValueString() const;
|
||||||
|
|
||||||
static void LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider);
|
static void LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider);
|
||||||
static int IdStrFromCmdId(int id)
|
static int IdStrFromCmdId(int id)
|
||||||
|
|
|
@ -196,7 +196,7 @@ inline constexpr auto SIDS_ACSCH = L"InverseCsch";
|
||||||
inline constexpr auto SIDS_COTH = L"Coth";
|
inline constexpr auto SIDS_COTH = L"Coth";
|
||||||
inline constexpr auto SIDS_ACOTH = L"InverseCoth";
|
inline constexpr auto SIDS_ACOTH = L"InverseCoth";
|
||||||
inline constexpr auto SIDS_TWOPOWX = L"TwoPowX";
|
inline constexpr auto SIDS_TWOPOWX = L"TwoPowX";
|
||||||
inline constexpr auto SIDS_LOGBASEX = L"LogBaseX";
|
inline constexpr auto SIDS_LOGBASEY = L"LogBaseY";
|
||||||
inline constexpr auto SIDS_ABS = L"Abs";
|
inline constexpr auto SIDS_ABS = L"Abs";
|
||||||
inline constexpr auto SIDS_FLOOR = L"Floor";
|
inline constexpr auto SIDS_FLOOR = L"Floor";
|
||||||
inline constexpr auto SIDS_CEIL = L"Ceil";
|
inline constexpr auto SIDS_CEIL = L"Ceil";
|
||||||
|
@ -352,7 +352,7 @@ inline constexpr std::array<std::wstring_view, 152> g_sids =
|
||||||
SIDS_COTH,
|
SIDS_COTH,
|
||||||
SIDS_ACOTH,
|
SIDS_ACOTH,
|
||||||
SIDS_TWOPOWX,
|
SIDS_TWOPOWX,
|
||||||
SIDS_LOGBASEX,
|
SIDS_LOGBASEY,
|
||||||
SIDS_ABS,
|
SIDS_ABS,
|
||||||
SIDS_FLOOR,
|
SIDS_FLOOR,
|
||||||
SIDS_CEIL,
|
SIDS_CEIL,
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
void RemoveLastOpndFromHistory();
|
void RemoveLastOpndFromHistory();
|
||||||
void AddBinOpToHistory(int nOpCode, bool isIntgerMode, bool fNoRepetition = true);
|
void AddBinOpToHistory(int nOpCode, bool isIntgerMode, bool fNoRepetition = true);
|
||||||
void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode);
|
void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode);
|
||||||
void AddUnaryOpToHistory(int nOpCode, bool fInv, ANGLE_TYPE angletype);
|
void AddUnaryOpToHistory(int nOpCode, bool fInv, AngleType angletype);
|
||||||
void AddOpenBraceToHistory();
|
void AddOpenBraceToHistory();
|
||||||
void AddCloseBraceToHistory();
|
void AddCloseBraceToHistory();
|
||||||
void PushLastOpndStart(int ichOpndStart = -1);
|
void PushLastOpndStart(int ichOpndStart = -1);
|
||||||
|
|
|
@ -4,11 +4,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// This is expected to be in same order as IDM_HEX, IDM_DEC, IDM_OCT, IDM_BIN
|
// This is expected to be in same order as IDM_HEX, IDM_DEC, IDM_OCT, IDM_BIN
|
||||||
enum eRADIX_TYPE
|
enum class RadixType
|
||||||
{
|
{
|
||||||
HEX_RADIX,
|
Hex,
|
||||||
DEC_RADIX,
|
Decimal,
|
||||||
OCT_RADIX,
|
Octal,
|
||||||
BIN_RADIX
|
Binary
|
||||||
};
|
};
|
||||||
typedef enum eRADIX_TYPE RADIX_TYPE;
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace CalcEngine
|
||||||
friend bool operator<=(Rational const& lhs, Rational const& rhs);
|
friend bool operator<=(Rational const& lhs, Rational const& rhs);
|
||||||
friend bool operator>=(Rational const& lhs, Rational const& rhs);
|
friend bool operator>=(Rational const& lhs, Rational const& rhs);
|
||||||
|
|
||||||
std::wstring ToString(uint32_t radix, NUMOBJ_FMT format, int32_t precision) const;
|
std::wstring ToString(uint32_t radix, NumberFormat format, int32_t precision) const;
|
||||||
uint64_t ToUInt64_t() const;
|
uint64_t ToUInt64_t() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -22,12 +22,12 @@ namespace CalcEngine::RationalMath
|
||||||
Rational Invert(Rational const& rat);
|
Rational Invert(Rational const& rat);
|
||||||
Rational Abs(Rational const& rat);
|
Rational Abs(Rational const& rat);
|
||||||
|
|
||||||
Rational Sin(Rational const& rat, ANGLE_TYPE angletype);
|
Rational Sin(Rational const& rat, AngleType angletype);
|
||||||
Rational Cos(Rational const& rat, ANGLE_TYPE angletype);
|
Rational Cos(Rational const& rat, AngleType angletype);
|
||||||
Rational Tan(Rational const& rat, ANGLE_TYPE angletype);
|
Rational Tan(Rational const& rat, AngleType angletype);
|
||||||
Rational ASin(Rational const& rat, ANGLE_TYPE angletype);
|
Rational ASin(Rational const& rat, AngleType angletype);
|
||||||
Rational ACos(Rational const& rat, ANGLE_TYPE angletype);
|
Rational ACos(Rational const& rat, AngleType angletype);
|
||||||
Rational ATan(Rational const& rat, ANGLE_TYPE angletype);
|
Rational ATan(Rational const& rat, AngleType angletype);
|
||||||
|
|
||||||
Rational Sinh(Rational const& rat);
|
Rational Sinh(Rational const& rat);
|
||||||
Rational Cosh(Rational const& rat);
|
Rational Cosh(Rational const& rat);
|
||||||
|
|
|
@ -50,15 +50,15 @@ namespace CalcManager::NumberFormattingUtils
|
||||||
/// <param name="value">the number</param>
|
/// <param name="value">the number</param>
|
||||||
unsigned int GetNumberDigitsWholeNumberPart(double value)
|
unsigned int GetNumberDigitsWholeNumberPart(double value)
|
||||||
{
|
{
|
||||||
return value == 0 ? 1 : (1 + (int)log10(abs(value)));
|
return value == 0 ? 1u : static_cast<unsigned int>(1 + max(0.0, log10(abs(value))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rounds the given double to the given number of significant digits
|
/// Rounds the given double to the given number of significant digits
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="num">input double</param>
|
/// <param name="num">input double</param>
|
||||||
/// <param name="numSignificant">int number of significant digits to round to</param>
|
/// <param name="numSignificant">unsigned int number of significant digits to round to</param>
|
||||||
wstring RoundSignificantDigits(double num, int numSignificant)
|
wstring RoundSignificantDigits(double num, unsigned int numSignificant)
|
||||||
{
|
{
|
||||||
wstringstream out(wstringstream::out);
|
wstringstream out(wstringstream::out);
|
||||||
out << fixed;
|
out << fixed;
|
||||||
|
|
|
@ -10,6 +10,6 @@ namespace CalcManager::NumberFormattingUtils
|
||||||
void TrimTrailingZeros(_Inout_ std::wstring& input);
|
void TrimTrailingZeros(_Inout_ std::wstring& input);
|
||||||
unsigned int GetNumberDigits(std::wstring value);
|
unsigned int GetNumberDigits(std::wstring value);
|
||||||
unsigned int GetNumberDigitsWholeNumberPart(double value);
|
unsigned int GetNumberDigitsWholeNumberPart(double value);
|
||||||
std::wstring RoundSignificantDigits(double value, int numberSignificantDigits);
|
std::wstring RoundSignificantDigits(double value, unsigned int numberSignificantDigits);
|
||||||
std::wstring ToScientificNumber(double number);
|
std::wstring ToScientificNumber(double number);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
target_sources(CalcManager PRIVATE
|
|
||||||
basex.cpp
|
|
||||||
conv.cpp
|
|
||||||
exp.cpp
|
|
||||||
fact.cpp
|
|
||||||
itrans.cpp
|
|
||||||
itransh.cpp
|
|
||||||
logic.cpp
|
|
||||||
num.cpp
|
|
||||||
rat.cpp
|
|
||||||
support.cpp
|
|
||||||
trans.cpp
|
|
||||||
transh.cpp
|
|
||||||
)
|
|
|
@ -303,17 +303,13 @@ PRAT numtorat(_In_ PNUMBER pin, uint32_t radix)
|
||||||
PNUMBER nRadixxtonum(_In_ PNUMBER a, uint32_t radix, int32_t precision)
|
PNUMBER nRadixxtonum(_In_ PNUMBER a, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
uint32_t bitmask;
|
|
||||||
uint32_t cdigits;
|
|
||||||
MANTTYPE* ptr;
|
|
||||||
|
|
||||||
PNUMBER sum = i32tonum(0, radix);
|
PNUMBER sum = i32tonum(0, radix);
|
||||||
PNUMBER powofnRadix = i32tonum(BASEX, radix);
|
PNUMBER powofnRadix = i32tonum(BASEX, radix);
|
||||||
|
|
||||||
// A large penalty is paid for conversion of digits no one will see anyway.
|
// A large penalty is paid for conversion of digits no one will see anyway.
|
||||||
// limit the digits to the minimum of the existing precision or the
|
// limit the digits to the minimum of the existing precision or the
|
||||||
// requested precision.
|
// requested precision.
|
||||||
cdigits = precision + 1;
|
uint32_t cdigits = precision + 1;
|
||||||
if (cdigits > (uint32_t)a->cdigit)
|
if (cdigits > (uint32_t)a->cdigit)
|
||||||
{
|
{
|
||||||
cdigits = (uint32_t)a->cdigit;
|
cdigits = (uint32_t)a->cdigit;
|
||||||
|
@ -323,10 +319,10 @@ PNUMBER nRadixxtonum(_In_ PNUMBER a, uint32_t radix, int32_t precision)
|
||||||
numpowi32(&powofnRadix, a->exp + (a->cdigit - cdigits), radix, precision);
|
numpowi32(&powofnRadix, a->exp + (a->cdigit - cdigits), radix, precision);
|
||||||
|
|
||||||
// Loop over all the relative digits from MSD to LSD
|
// Loop over all the relative digits from MSD to LSD
|
||||||
for (ptr = &(a->mant[a->cdigit - 1]); cdigits > 0; ptr--, cdigits--)
|
for (MANTTYPE* ptr = &(a->mant[a->cdigit - 1]); cdigits > 0; ptr--, cdigits--)
|
||||||
{
|
{
|
||||||
// Loop over all the bits from MSB to LSB
|
// Loop over all the bits from MSB to LSB
|
||||||
for (bitmask = BASEX / 2; bitmask > 0; bitmask /= 2)
|
for (uint32_t bitmask = BASEX / 2; bitmask > 0; bitmask /= 2)
|
||||||
{
|
{
|
||||||
addnum(&sum, sum, radix);
|
addnum(&sum, sum, radix);
|
||||||
if (*ptr & bitmask)
|
if (*ptr & bitmask)
|
||||||
|
@ -368,9 +364,7 @@ PNUMBER numtonRadixx(_In_ PNUMBER a, uint32_t radix)
|
||||||
ptrdigit += a->cdigit - 1;
|
ptrdigit += a->cdigit - 1;
|
||||||
|
|
||||||
PNUMBER thisdigit = nullptr; // thisdigit holds the current digit of a
|
PNUMBER thisdigit = nullptr; // thisdigit holds the current digit of a
|
||||||
// being summed into result.
|
for (int32_t idigit = 0; idigit < a->cdigit; idigit++)
|
||||||
int32_t idigit; // idigit is the iterate of digits in a.
|
|
||||||
for (idigit = 0; idigit < a->cdigit; idigit++)
|
|
||||||
{
|
{
|
||||||
mulnumx(&pnumret, num_radix);
|
mulnumx(&pnumret, num_radix);
|
||||||
// WARNING:
|
// WARNING:
|
||||||
|
@ -628,11 +622,10 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis
|
||||||
MANTTYPE* pmant = pnumret->mant + numberString.length() - 1;
|
MANTTYPE* pmant = pnumret->mant + numberString.length() - 1;
|
||||||
|
|
||||||
uint8_t state = START; // state is the state of the input state machine.
|
uint8_t state = START; // state is the state of the input state machine.
|
||||||
wchar_t curChar;
|
|
||||||
for (const auto& c : numberString)
|
for (const auto& c : numberString)
|
||||||
{
|
{
|
||||||
// If the character is the decimal separator, use L'.' for the purposes of the state machine.
|
// If the character is the decimal separator, use L'.' for the purposes of the state machine.
|
||||||
curChar = (c == g_decimalSeparator ? L'.' : c);
|
wchar_t curChar = (c == g_decimalSeparator ? L'.' : c);
|
||||||
|
|
||||||
// Switch states based on the character we encountered
|
// Switch states based on the character we encountered
|
||||||
switch (curChar)
|
switch (curChar)
|
||||||
|
@ -1032,13 +1025,10 @@ int32_t numtoi32(_In_ PNUMBER pnum, uint32_t radix)
|
||||||
|
|
||||||
bool stripzeroesnum(_Inout_ PNUMBER pnum, int32_t starting)
|
bool stripzeroesnum(_Inout_ PNUMBER pnum, int32_t starting)
|
||||||
{
|
{
|
||||||
MANTTYPE* pmant;
|
|
||||||
int32_t cdigits;
|
|
||||||
bool fstrip = false;
|
bool fstrip = false;
|
||||||
|
|
||||||
// point pmant to the LeastCalculatedDigit
|
// point pmant to the LeastCalculatedDigit
|
||||||
pmant = pnum->mant;
|
MANTTYPE* pmant = pnum->mant;
|
||||||
cdigits = pnum->cdigit;
|
int32_t cdigits = pnum->cdigit;
|
||||||
// point pmant to the LSD
|
// point pmant to the LSD
|
||||||
if (cdigits > starting)
|
if (cdigits > starting)
|
||||||
{
|
{
|
||||||
|
@ -1073,27 +1063,27 @@ bool stripzeroesnum(_Inout_ PNUMBER pnum, int32_t starting)
|
||||||
// FUNCTION: NumberToString
|
// FUNCTION: NumberToString
|
||||||
//
|
//
|
||||||
// ARGUMENTS: number representation
|
// ARGUMENTS: number representation
|
||||||
// fmt, one of FMT_FLOAT FMT_SCIENTIFIC or
|
// fmt, one of NumberFormat::Float, NumberFormat::Scientific or
|
||||||
// FMT_ENGINEERING
|
// NumberFormat::Engineering
|
||||||
// integer radix and int32_t precision value
|
// integer radix and int32_t precision value
|
||||||
//
|
//
|
||||||
// RETURN: String representation of number.
|
// RETURN: String representation of number.
|
||||||
//
|
//
|
||||||
// DESCRIPTION: Converts a number to it's string
|
// DESCRIPTION: Converts a number to its string
|
||||||
// representation.
|
// representation.
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_t precision)
|
wstring NumberToString(_Inout_ PNUMBER& pnum, NumberFormat format, uint32_t radix, int32_t precision)
|
||||||
{
|
{
|
||||||
stripzeroesnum(pnum, precision + 2);
|
stripzeroesnum(pnum, precision + 2);
|
||||||
int32_t length = pnum->cdigit;
|
int32_t length = pnum->cdigit;
|
||||||
int32_t exponent = pnum->exp + length; // Actual number of digits to the left of decimal
|
int32_t exponent = pnum->exp + length; // Actual number of digits to the left of decimal
|
||||||
|
|
||||||
int32_t oldFormat = format;
|
NumberFormat oldFormat = format;
|
||||||
if (exponent > precision && format == FMT_FLOAT)
|
if (exponent > precision && format == NumberFormat::Float)
|
||||||
{
|
{
|
||||||
// Force scientific mode to prevent user from assuming 33rd digit is exact.
|
// Force scientific mode to prevent user from assuming 33rd digit is exact.
|
||||||
format = FMT_SCIENTIFIC;
|
format = NumberFormat::Scientific;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make length small enough to fit in pret.
|
// Make length small enough to fit in pret.
|
||||||
|
@ -1113,7 +1103,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
|
||||||
divnum(&round, num_two, radix, precision);
|
divnum(&round, num_two, radix, precision);
|
||||||
|
|
||||||
// Make round number exponent one below the LSD for the number.
|
// Make round number exponent one below the LSD for the number.
|
||||||
if (exponent > 0 || format == FMT_FLOAT)
|
if (exponent > 0 || format == NumberFormat::Float)
|
||||||
{
|
{
|
||||||
round->exp = pnum->exp + pnum->cdigit - round->cdigit - precision;
|
round->exp = pnum->exp + pnum->cdigit - round->cdigit - precision;
|
||||||
}
|
}
|
||||||
|
@ -1126,7 +1116,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
|
||||||
round->sign = pnum->sign;
|
round->sign = pnum->sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == FMT_FLOAT)
|
if (format == NumberFormat::Float)
|
||||||
{
|
{
|
||||||
// Figure out if the exponent will fill more space than the non-exponent field.
|
// Figure out if the exponent will fill more space than the non-exponent field.
|
||||||
if ((length - exponent > precision) || (exponent > precision + 3))
|
if ((length - exponent > precision) || (exponent > precision + 3))
|
||||||
|
@ -1140,7 +1130,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
|
||||||
{
|
{
|
||||||
// Case where too many zeros are to the right or left of the
|
// Case where too many zeros are to the right or left of the
|
||||||
// decimal pt. And we are forced to switch to scientific form.
|
// decimal pt. And we are forced to switch to scientific form.
|
||||||
format = FMT_SCIENTIFIC;
|
format = NumberFormat::Scientific;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (length + abs(exponent) < precision && round)
|
else if (length + abs(exponent) < precision && round)
|
||||||
|
@ -1173,13 +1163,13 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
|
||||||
int32_t eout = exponent - 1; // Displayed exponent.
|
int32_t eout = exponent - 1; // Displayed exponent.
|
||||||
MANTTYPE* pmant = pnum->mant + pnum->cdigit - 1;
|
MANTTYPE* pmant = pnum->mant + pnum->cdigit - 1;
|
||||||
// Case where too many digits are to the left of the decimal or
|
// Case where too many digits are to the left of the decimal or
|
||||||
// FMT_SCIENTIFIC or FMT_ENGINEERING was specified.
|
// NumberFormat::Scientific or NumberFormat::Engineering was specified.
|
||||||
if ((format == FMT_SCIENTIFIC) || (format == FMT_ENGINEERING))
|
if ((format == NumberFormat::Scientific) || (format == NumberFormat::Engineering))
|
||||||
{
|
{
|
||||||
useSciForm = true;
|
useSciForm = true;
|
||||||
if (eout != 0)
|
if (eout != 0)
|
||||||
{
|
{
|
||||||
if (format == FMT_ENGINEERING)
|
if (format == NumberFormat::Engineering)
|
||||||
{
|
{
|
||||||
exponent = (eout % 3);
|
exponent = (eout % 3);
|
||||||
eout -= exponent;
|
eout -= exponent;
|
||||||
|
@ -1280,7 +1270,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
|
||||||
// ARGUMENTS:
|
// ARGUMENTS:
|
||||||
// PRAT *representation of a number.
|
// PRAT *representation of a number.
|
||||||
// i32 representation of base to dump to screen.
|
// i32 representation of base to dump to screen.
|
||||||
// fmt, one of FMT_FLOAT FMT_SCIENTIFIC or FMT_ENGINEERING
|
// fmt, one of NumberFormat::Float, NumberFormat::Scientific, or NumberFormat::Engineering
|
||||||
// precision uint32_t
|
// precision uint32_t
|
||||||
//
|
//
|
||||||
// RETURN: string
|
// RETURN: string
|
||||||
|
@ -1293,7 +1283,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_
|
||||||
// why a pointer to the rational is passed in.
|
// why a pointer to the rational is passed in.
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
wstring RatToString(_Inout_ PRAT& prat, int format, uint32_t radix, int32_t precision)
|
wstring RatToString(_Inout_ PRAT& prat, NumberFormat format, uint32_t radix, int32_t precision)
|
||||||
{
|
{
|
||||||
PNUMBER p = RatToNumber(prat, radix, precision);
|
PNUMBER p = RatToNumber(prat, radix, precision);
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,6 @@ void exprat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
|
||||||
{
|
{
|
||||||
PRAT pwr = nullptr;
|
PRAT pwr = nullptr;
|
||||||
PRAT pint = nullptr;
|
PRAT pint = nullptr;
|
||||||
int32_t intpwr;
|
|
||||||
|
|
||||||
if (rat_gt(*px, rat_max_exp, precision) || rat_lt(*px, rat_min_exp, precision))
|
if (rat_gt(*px, rat_max_exp, precision) || rat_lt(*px, rat_min_exp, precision))
|
||||||
{
|
{
|
||||||
|
@ -76,7 +75,7 @@ void exprat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
intrat(&pint, radix, precision);
|
intrat(&pint, radix, precision);
|
||||||
|
|
||||||
intpwr = rattoi32(pint, radix, precision);
|
const int32_t intpwr = rattoi32(pint, radix, precision);
|
||||||
ratpowi32(&pwr, intpwr, precision);
|
ratpowi32(&pwr, intpwr, precision);
|
||||||
|
|
||||||
subrat(px, pint, precision);
|
subrat(px, pint, precision);
|
||||||
|
@ -153,7 +152,6 @@ void _lograt(PRAT* px, int32_t precision)
|
||||||
void lograt(_Inout_ PRAT* px, int32_t precision)
|
void lograt(_Inout_ PRAT* px, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
bool fneglog;
|
|
||||||
PRAT pwr = nullptr; // pwr is the large scaling factor.
|
PRAT pwr = nullptr; // pwr is the large scaling factor.
|
||||||
PRAT offset = nullptr; // offset is the incremental scaling factor.
|
PRAT offset = nullptr; // offset is the incremental scaling factor.
|
||||||
|
|
||||||
|
@ -164,12 +162,10 @@ void lograt(_Inout_ PRAT* px, int32_t precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get number > 1, for scaling
|
// Get number > 1, for scaling
|
||||||
fneglog = rat_lt(*px, rat_one, precision);
|
bool fneglog = rat_lt(*px, rat_one, precision);
|
||||||
if (fneglog)
|
if (fneglog)
|
||||||
{
|
{
|
||||||
// WARNING: This is equivalent to doing *px = 1 / *px
|
PNUMBER pnumtemp = (*px)->pp;
|
||||||
PNUMBER pnumtemp = nullptr;
|
|
||||||
pnumtemp = (*px)->pp;
|
|
||||||
(*px)->pp = (*px)->pq;
|
(*px)->pp = (*px)->pq;
|
||||||
(*px)->pq = pnumtemp;
|
(*px)->pq = pnumtemp;
|
||||||
}
|
}
|
||||||
|
@ -178,10 +174,7 @@ void lograt(_Inout_ PRAT* px, int32_t precision)
|
||||||
// log(x*2^(BASEXPWR*k)) = BASEXPWR*k*log(2)+log(x)
|
// log(x*2^(BASEXPWR*k)) = BASEXPWR*k*log(2)+log(x)
|
||||||
if (LOGRAT2(*px) > 1)
|
if (LOGRAT2(*px) > 1)
|
||||||
{
|
{
|
||||||
// Take advantage of px's base BASEX to scale quickly down to
|
const int32_t intpwr = LOGRAT2(*px) - 1;
|
||||||
// a reasonable range.
|
|
||||||
int32_t intpwr;
|
|
||||||
intpwr = LOGRAT2(*px) - 1;
|
|
||||||
(*px)->pq->exp += intpwr;
|
(*px)->pq->exp += intpwr;
|
||||||
pwr = i32torat(intpwr * BASEXPWR);
|
pwr = i32torat(intpwr * BASEXPWR);
|
||||||
mulrat(&pwr, ln_two, precision);
|
mulrat(&pwr, ln_two, precision);
|
||||||
|
@ -448,10 +441,9 @@ void powratcomp(_Inout_ PRAT* px, _In_ PRAT y, uint32_t radix, int32_t precision
|
||||||
{
|
{
|
||||||
// If power is an integer let ratpowi32 deal with it.
|
// If power is an integer let ratpowi32 deal with it.
|
||||||
PRAT iy = nullptr;
|
PRAT iy = nullptr;
|
||||||
int32_t inty;
|
|
||||||
DUPRAT(iy, y);
|
DUPRAT(iy, y);
|
||||||
subrat(&iy, podd, precision);
|
subrat(&iy, podd, precision);
|
||||||
inty = rattoi32(iy, radix, precision);
|
int32_t inty = rattoi32(iy, radix, precision);
|
||||||
|
|
||||||
PRAT plnx = nullptr;
|
PRAT plnx = nullptr;
|
||||||
DUPRAT(plnx, *px);
|
DUPRAT(plnx, *px);
|
||||||
|
|
|
@ -67,13 +67,9 @@ void _gamma(PRAT* pn, uint32_t radix, int32_t precision)
|
||||||
PRAT sum = nullptr;
|
PRAT sum = nullptr;
|
||||||
PRAT err = nullptr;
|
PRAT err = nullptr;
|
||||||
PRAT mpy = nullptr;
|
PRAT mpy = nullptr;
|
||||||
PRAT ratprec = nullptr;
|
|
||||||
PRAT ratRadix = nullptr;
|
|
||||||
int32_t oldprec;
|
|
||||||
|
|
||||||
// Set up constants and initial conditions
|
// Set up constants and initial conditions
|
||||||
oldprec = precision;
|
PRAT ratprec = i32torat(precision);
|
||||||
ratprec = i32torat(oldprec);
|
|
||||||
|
|
||||||
// Find the best 'A' for convergence to the required precision.
|
// Find the best 'A' for convergence to the required precision.
|
||||||
a = i32torat(radix);
|
a = i32torat(radix);
|
||||||
|
@ -102,7 +98,7 @@ void _gamma(PRAT* pn, uint32_t radix, int32_t precision)
|
||||||
exprat(&tmp, radix, precision);
|
exprat(&tmp, radix, precision);
|
||||||
mulrat(&term, tmp, precision);
|
mulrat(&term, tmp, precision);
|
||||||
lograt(&term, precision);
|
lograt(&term, precision);
|
||||||
ratRadix = i32torat(radix);
|
const auto ratRadix = i32torat(radix);
|
||||||
DUPRAT(tmp, ratRadix);
|
DUPRAT(tmp, ratRadix);
|
||||||
lograt(&tmp, precision);
|
lograt(&tmp, precision);
|
||||||
subrat(&term, tmp, precision);
|
subrat(&term, tmp, precision);
|
||||||
|
@ -173,7 +169,6 @@ void _gamma(PRAT* pn, uint32_t radix, int32_t precision)
|
||||||
mulrat(&sum, mpy, precision);
|
mulrat(&sum, mpy, precision);
|
||||||
|
|
||||||
// And cleanup
|
// And cleanup
|
||||||
precision = oldprec;
|
|
||||||
destroyrat(ratprec);
|
destroyrat(ratprec);
|
||||||
destroyrat(err);
|
destroyrat(err);
|
||||||
destroyrat(term);
|
destroyrat(term);
|
||||||
|
|
|
@ -17,17 +17,17 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#include "ratpak.h"
|
#include "ratpak.h"
|
||||||
|
|
||||||
void ascalerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, int32_t precision)
|
void ascalerat(_Inout_ PRAT* pa, AngleType angletype, int32_t precision)
|
||||||
{
|
{
|
||||||
switch (angletype)
|
switch (angletype)
|
||||||
{
|
{
|
||||||
case ANGLE_RAD:
|
case AngleType::Radians:
|
||||||
break;
|
break;
|
||||||
case ANGLE_DEG:
|
case AngleType::Degrees:
|
||||||
divrat(pa, two_pi, precision);
|
divrat(pa, two_pi, precision);
|
||||||
mulrat(pa, rat_360, precision);
|
mulrat(pa, rat_360, precision);
|
||||||
break;
|
break;
|
||||||
case ANGLE_GRAD:
|
case AngleType::Gradians:
|
||||||
divrat(pa, two_pi, precision);
|
divrat(pa, two_pi, precision);
|
||||||
mulrat(pa, rat_400, precision);
|
mulrat(pa, rat_400, precision);
|
||||||
break;
|
break;
|
||||||
|
@ -76,7 +76,7 @@ void _asinrat(PRAT* px, int32_t precision)
|
||||||
DESTROYTAYLOR();
|
DESTROYTAYLOR();
|
||||||
}
|
}
|
||||||
|
|
||||||
void asinanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void asinanglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
asinrat(pa, radix, precision);
|
asinrat(pa, radix, precision);
|
||||||
|
@ -164,7 +164,7 @@ void asinrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void acosanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void acosanglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
acosrat(pa, radix, precision);
|
acosrat(pa, radix, precision);
|
||||||
|
@ -249,7 +249,7 @@ void acosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void atananglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void atananglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
atanrat(pa, radix, precision);
|
atanrat(pa, radix, precision);
|
||||||
|
|
|
@ -21,7 +21,6 @@ void lshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
PRAT pwr = nullptr;
|
PRAT pwr = nullptr;
|
||||||
int32_t intb;
|
|
||||||
|
|
||||||
intrat(pa, radix, precision);
|
intrat(pa, radix, precision);
|
||||||
if (!zernum((*pa)->pp))
|
if (!zernum((*pa)->pp))
|
||||||
|
@ -32,7 +31,7 @@ void lshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
|
||||||
// Don't attempt lsh of anything big
|
// Don't attempt lsh of anything big
|
||||||
throw(CALC_E_DOMAIN);
|
throw(CALC_E_DOMAIN);
|
||||||
}
|
}
|
||||||
intb = rattoi32(b, radix, precision);
|
const int32_t intb = rattoi32(b, radix, precision);
|
||||||
DUPRAT(pwr, rat_two);
|
DUPRAT(pwr, rat_two);
|
||||||
ratpowi32(&pwr, intb, precision);
|
ratpowi32(&pwr, intb, precision);
|
||||||
mulrat(pa, pwr, precision);
|
mulrat(pa, pwr, precision);
|
||||||
|
@ -44,7 +43,6 @@ void rshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
PRAT pwr = nullptr;
|
PRAT pwr = nullptr;
|
||||||
int32_t intb;
|
|
||||||
|
|
||||||
intrat(pa, radix, precision);
|
intrat(pa, radix, precision);
|
||||||
if (!zernum((*pa)->pp))
|
if (!zernum((*pa)->pp))
|
||||||
|
@ -55,7 +53,7 @@ void rshrat(_Inout_ PRAT* pa, _In_ PRAT b, uint32_t radix, int32_t precision)
|
||||||
// Don't attempt rsh of anything big and negative.
|
// Don't attempt rsh of anything big and negative.
|
||||||
throw(CALC_E_DOMAIN);
|
throw(CALC_E_DOMAIN);
|
||||||
}
|
}
|
||||||
intb = rattoi32(b, radix, precision);
|
const int32_t intb = rattoi32(b, radix, precision);
|
||||||
DUPRAT(pwr, rat_two);
|
DUPRAT(pwr, rat_two);
|
||||||
ratpowi32(&pwr, intb, precision);
|
ratpowi32(&pwr, intb, precision);
|
||||||
divrat(pa, pwr, precision);
|
divrat(pa, pwr, precision);
|
||||||
|
|
|
@ -67,8 +67,7 @@ void _addnum(PNUMBER* pa, PNUMBER b, uint32_t radix)
|
||||||
MANTTYPE* pcha; // pcha is a pointer to the mantissa of a.
|
MANTTYPE* pcha; // pcha is a pointer to the mantissa of a.
|
||||||
MANTTYPE* pchb; // pchb is a pointer to the mantissa of b.
|
MANTTYPE* pchb; // pchb is a pointer to the mantissa of b.
|
||||||
MANTTYPE* pchc; // pchc is a pointer to the mantissa of c.
|
MANTTYPE* pchc; // pchc is a pointer to the mantissa of c.
|
||||||
int32_t cdigits; // cdigits is the max count of the digits results
|
int32_t cdigits; // cdigits is the max count of the digits results used as a counter.
|
||||||
// used as a counter.
|
|
||||||
int32_t mexp; // mexp is the exponent of the result.
|
int32_t mexp; // mexp is the exponent of the result.
|
||||||
MANTTYPE da; // da is a single 'digit' after possible padding.
|
MANTTYPE da; // da is a single 'digit' after possible padding.
|
||||||
MANTTYPE db; // db is a single 'digit' after possible padding.
|
MANTTYPE db; // db is a single 'digit' after possible padding.
|
||||||
|
@ -558,38 +557,26 @@ bool equnum(_In_ PNUMBER a, _In_ PNUMBER b)
|
||||||
bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b)
|
bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b)
|
||||||
|
|
||||||
{
|
{
|
||||||
int32_t diff;
|
int32_t diff = (a->cdigit + a->exp) - (b->cdigit + b->exp);
|
||||||
MANTTYPE* pa;
|
|
||||||
MANTTYPE* pb;
|
|
||||||
int32_t cdigits;
|
|
||||||
int32_t ccdigits;
|
|
||||||
MANTTYPE da;
|
|
||||||
MANTTYPE db;
|
|
||||||
|
|
||||||
diff = (a->cdigit + a->exp) - (b->cdigit + b->exp);
|
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
{
|
{
|
||||||
// The exponent of a is less than b
|
// The exponent of a is less than b
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (diff > 0)
|
if (diff > 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
MANTTYPE* pa = a->mant;
|
||||||
{
|
MANTTYPE* pb = b->mant;
|
||||||
pa = a->mant;
|
|
||||||
pb = b->mant;
|
|
||||||
pa += a->cdigit - 1;
|
pa += a->cdigit - 1;
|
||||||
pb += b->cdigit - 1;
|
pb += b->cdigit - 1;
|
||||||
cdigits = max(a->cdigit, b->cdigit);
|
int32_t cdigits = max(a->cdigit, b->cdigit);
|
||||||
ccdigits = cdigits;
|
int32_t ccdigits = cdigits;
|
||||||
for (; cdigits > 0; cdigits--)
|
for (; cdigits > 0; cdigits--)
|
||||||
{
|
{
|
||||||
da = ((cdigits > (ccdigits - a->cdigit)) ? *pa-- : 0);
|
MANTTYPE da = ((cdigits > (ccdigits - a->cdigit)) ? *pa-- : 0);
|
||||||
db = ((cdigits > (ccdigits - b->cdigit)) ? *pb-- : 0);
|
MANTTYPE db = ((cdigits > (ccdigits - b->cdigit)) ? *pb-- : 0);
|
||||||
diff = da - db;
|
diff = da - db;
|
||||||
if (diff)
|
if (diff)
|
||||||
{
|
{
|
||||||
|
@ -598,8 +585,6 @@ bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b)
|
||||||
}
|
}
|
||||||
// In this case, they are equal.
|
// In this case, they are equal.
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -31,25 +31,20 @@ static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculat
|
||||||
typedef uint32_t MANTTYPE;
|
typedef uint32_t MANTTYPE;
|
||||||
typedef uint64_t TWO_MANTTYPE;
|
typedef uint64_t TWO_MANTTYPE;
|
||||||
|
|
||||||
enum eNUMOBJ_FMT
|
enum class NumberFormat
|
||||||
{
|
{
|
||||||
FMT_FLOAT, // returns floating point, or exponential if number is too big
|
Float, // returns floating point, or exponential if number is too big
|
||||||
FMT_SCIENTIFIC, // always returns scientific notation
|
Scientific, // always returns scientific notation
|
||||||
FMT_ENGINEERING // always returns engineering notation such that exponent is a multiple of 3
|
Engineering // always returns engineering notation such that exponent is a multiple of 3
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eANGLE_TYPE
|
enum class AngleType
|
||||||
{
|
{
|
||||||
ANGLE_DEG, // Calculate trig using 360 degrees per revolution
|
Degrees, // Calculate trig using 360 degrees per revolution
|
||||||
ANGLE_RAD, // Calculate trig using 2 pi radians per revolution
|
Radians, // Calculate trig using 2 pi radians per revolution
|
||||||
ANGLE_GRAD // Calculate trig using 400 gradients per revolution
|
Gradians // Calculate trig using 400 gradians per revolution
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum eNUMOBJ_FMT NUMOBJ_FMT;
|
|
||||||
typedef enum eANGLE_TYPE ANGLE_TYPE;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// NUMBER type is a representation of a generic sized generic radix number
|
// NUMBER type is a representation of a generic sized generic radix number
|
||||||
|
@ -341,10 +336,10 @@ extern bool equnum(_In_ PNUMBER a, _In_ PNUMBER b); // returns true of a == b
|
||||||
extern bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b); // returns true of a < b
|
extern bool lessnum(_In_ PNUMBER a, _In_ PNUMBER b); // returns true of a < b
|
||||||
extern bool zernum(_In_ PNUMBER a); // returns true of a == 0
|
extern bool zernum(_In_ PNUMBER a); // returns true of a == 0
|
||||||
extern bool zerrat(_In_ PRAT a); // returns true if a == 0/q
|
extern bool zerrat(_In_ PRAT a); // returns true if a == 0/q
|
||||||
extern std::wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_t precision);
|
extern std::wstring NumberToString(_Inout_ PNUMBER& pnum, NumberFormat format, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a text representation of a PRAT
|
// returns a text representation of a PRAT
|
||||||
extern std::wstring RatToString(_Inout_ PRAT& prat, int format, uint32_t radix, int32_t precision);
|
extern std::wstring RatToString(_Inout_ PRAT& prat, NumberFormat format, uint32_t radix, int32_t precision);
|
||||||
// converts a PRAT into a PNUMBER
|
// converts a PRAT into a PNUMBER
|
||||||
extern PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision);
|
extern PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision);
|
||||||
// flattens a PRAT by converting it to a PNUMBER and back to a PRAT
|
// flattens a PRAT by converting it to a PNUMBER and back to a PRAT
|
||||||
|
@ -376,7 +371,7 @@ extern PRAT _createrat(void);
|
||||||
|
|
||||||
// returns a new rat structure with the acos of x->p/x->q taking into account
|
// returns a new rat structure with the acos of x->p/x->q taking into account
|
||||||
// angle type
|
// angle type
|
||||||
extern void acosanglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
|
extern void acosanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the acosh of x->p/x->q
|
// returns a new rat structure with the acosh of x->p/x->q
|
||||||
extern void acoshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
extern void acoshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
|
@ -386,7 +381,7 @@ extern void acosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the asin of x->p/x->q taking into account
|
// returns a new rat structure with the asin of x->p/x->q taking into account
|
||||||
// angle type
|
// angle type
|
||||||
extern void asinanglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
|
extern void asinanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
extern void asinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
extern void asinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
// returns a new rat structure with the asinh of x->p/x->q
|
// returns a new rat structure with the asinh of x->p/x->q
|
||||||
|
@ -396,7 +391,7 @@ extern void asinrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the atan of x->p/x->q taking into account
|
// returns a new rat structure with the atan of x->p/x->q taking into account
|
||||||
// angle type
|
// angle type
|
||||||
extern void atananglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
|
extern void atananglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the atanh of x->p/x->q
|
// returns a new rat structure with the atanh of x->p/x->q
|
||||||
extern void atanhrat(_Inout_ PRAT* px, int32_t precision);
|
extern void atanhrat(_Inout_ PRAT* px, int32_t precision);
|
||||||
|
@ -412,7 +407,7 @@ extern void cosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the cos of x->p/x->q taking into account
|
// returns a new rat structure with the cos of x->p/x->q taking into account
|
||||||
// angle type
|
// angle type
|
||||||
extern void cosanglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
|
extern void cosanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the exp of x->p/x->q this should not be called explicitly.
|
// returns a new rat structure with the exp of x->p/x->q this should not be called explicitly.
|
||||||
extern void _exprat(_Inout_ PRAT* px, int32_t precision);
|
extern void _exprat(_Inout_ PRAT* px, int32_t precision);
|
||||||
|
@ -435,14 +430,14 @@ extern void sinrat(_Inout_ PRAT* px);
|
||||||
|
|
||||||
// returns a new rat structure with the sin of x->p/x->q taking into account
|
// returns a new rat structure with the sin of x->p/x->q taking into account
|
||||||
// angle type
|
// angle type
|
||||||
extern void sinanglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
|
extern void sinanglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
extern void tanhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
extern void tanhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
extern void tanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
extern void tanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
// returns a new rat structure with the tan of x->p/x->q taking into account
|
// returns a new rat structure with the tan of x->p/x->q taking into account
|
||||||
// angle type
|
// angle type
|
||||||
extern void tananglerat(_Inout_ PRAT* px, ANGLE_TYPE angletype, uint32_t radix, int32_t precision);
|
extern void tananglerat(_Inout_ PRAT* px, AngleType angletype, uint32_t radix, int32_t precision);
|
||||||
|
|
||||||
extern void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER* const src);
|
extern void _dupnum(_In_ PNUMBER dest, _In_ const NUMBER* const src);
|
||||||
|
|
||||||
|
|
|
@ -596,15 +596,13 @@ void _dumprawrat(_In_ const wchar_t* varname, _In_ PRAT rat, wostream& out)
|
||||||
void _dumprawnum(_In_ const wchar_t* varname, _In_ PNUMBER num, wostream& out)
|
void _dumprawnum(_In_ const wchar_t* varname, _In_ PNUMBER num, wostream& out)
|
||||||
|
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
out << L"NUMBER " << varname << L" = {\n";
|
out << L"NUMBER " << varname << L" = {\n";
|
||||||
out << L"\t" << num->sign << L",\n";
|
out << L"\t" << num->sign << L",\n";
|
||||||
out << L"\t" << num->cdigit << L",\n";
|
out << L"\t" << num->cdigit << L",\n";
|
||||||
out << L"\t" << num->exp << L",\n";
|
out << L"\t" << num->exp << L",\n";
|
||||||
out << L"\t{ ";
|
out << L"\t{ ";
|
||||||
|
|
||||||
for (i = 0; i < num->cdigit; i++)
|
for (int i = 0; i < num->cdigit; i++)
|
||||||
{
|
{
|
||||||
out << L" " << num->mant[i] << L",";
|
out << L" " << num->mant[i] << L",";
|
||||||
}
|
}
|
||||||
|
@ -681,10 +679,9 @@ void trimit(_Inout_ PRAT* px, int32_t precision)
|
||||||
{
|
{
|
||||||
if (!g_ftrueinfinite)
|
if (!g_ftrueinfinite)
|
||||||
{
|
{
|
||||||
int32_t trim;
|
|
||||||
PNUMBER pp = (*px)->pp;
|
PNUMBER pp = (*px)->pp;
|
||||||
PNUMBER pq = (*px)->pq;
|
PNUMBER pq = (*px)->pq;
|
||||||
trim = g_ratio * (min((pp->cdigit + pp->exp), (pq->cdigit + pq->exp)) - 1) - precision;
|
int32_t trim = g_ratio * (min((pp->cdigit + pp->exp), (pq->cdigit + pq->exp)) - 1) - precision;
|
||||||
if (trim > g_ratio)
|
if (trim > g_ratio)
|
||||||
{
|
{
|
||||||
trim /= g_ratio;
|
trim /= g_ratio;
|
||||||
|
|
|
@ -16,17 +16,17 @@
|
||||||
|
|
||||||
#include "ratpak.h"
|
#include "ratpak.h"
|
||||||
|
|
||||||
void scalerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void scalerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
{
|
{
|
||||||
switch (angletype)
|
switch (angletype)
|
||||||
{
|
{
|
||||||
case ANGLE_RAD:
|
case AngleType::Radians:
|
||||||
scale2pi(pa, radix, precision);
|
scale2pi(pa, radix, precision);
|
||||||
break;
|
break;
|
||||||
case ANGLE_DEG:
|
case AngleType::Degrees:
|
||||||
scale(pa, rat_360, radix, precision);
|
scale(pa, rat_360, radix, precision);
|
||||||
break;
|
break;
|
||||||
case ANGLE_GRAD:
|
case AngleType::Gradians:
|
||||||
scale(pa, rat_400, radix, precision);
|
scale(pa, rat_400, radix, precision);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -98,13 +98,13 @@ void sinrat(PRAT* px, uint32_t radix, int32_t precision)
|
||||||
_sinrat(px, precision);
|
_sinrat(px, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sinanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void sinanglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
scalerat(pa, angletype, radix, precision);
|
scalerat(pa, angletype, radix, precision);
|
||||||
switch (angletype)
|
switch (angletype)
|
||||||
{
|
{
|
||||||
case ANGLE_DEG:
|
case AngleType::Degrees:
|
||||||
if (rat_gt(*pa, rat_180, precision))
|
if (rat_gt(*pa, rat_180, precision))
|
||||||
{
|
{
|
||||||
subrat(pa, rat_360, precision);
|
subrat(pa, rat_360, precision);
|
||||||
|
@ -112,7 +112,7 @@ void sinanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t
|
||||||
divrat(pa, rat_180, precision);
|
divrat(pa, rat_180, precision);
|
||||||
mulrat(pa, pi, precision);
|
mulrat(pa, pi, precision);
|
||||||
break;
|
break;
|
||||||
case ANGLE_GRAD:
|
case AngleType::Gradians:
|
||||||
if (rat_gt(*pa, rat_200, precision))
|
if (rat_gt(*pa, rat_200, precision))
|
||||||
{
|
{
|
||||||
subrat(pa, rat_400, precision);
|
subrat(pa, rat_400, precision);
|
||||||
|
@ -193,13 +193,13 @@ void cosrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
|
||||||
_cosrat(px, radix, precision);
|
_cosrat(px, radix, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void cosanglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
scalerat(pa, angletype, radix, precision);
|
scalerat(pa, angletype, radix, precision);
|
||||||
switch (angletype)
|
switch (angletype)
|
||||||
{
|
{
|
||||||
case ANGLE_DEG:
|
case AngleType::Degrees:
|
||||||
if (rat_gt(*pa, rat_180, precision))
|
if (rat_gt(*pa, rat_180, precision))
|
||||||
{
|
{
|
||||||
PRAT ptmp = nullptr;
|
PRAT ptmp = nullptr;
|
||||||
|
@ -211,7 +211,7 @@ void cosanglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t
|
||||||
divrat(pa, rat_180, precision);
|
divrat(pa, rat_180, precision);
|
||||||
mulrat(pa, pi, precision);
|
mulrat(pa, pi, precision);
|
||||||
break;
|
break;
|
||||||
case ANGLE_GRAD:
|
case AngleType::Gradians:
|
||||||
if (rat_gt(*pa, rat_200, precision))
|
if (rat_gt(*pa, rat_200, precision))
|
||||||
{
|
{
|
||||||
PRAT ptmp = nullptr;
|
PRAT ptmp = nullptr;
|
||||||
|
@ -263,13 +263,13 @@ void tanrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
|
||||||
_tanrat(px, radix, precision);
|
_tanrat(px, radix, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tananglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t precision)
|
void tananglerat(_Inout_ PRAT* pa, AngleType angletype, uint32_t radix, int32_t precision)
|
||||||
|
|
||||||
{
|
{
|
||||||
scalerat(pa, angletype, radix, precision);
|
scalerat(pa, angletype, radix, precision);
|
||||||
switch (angletype)
|
switch (angletype)
|
||||||
{
|
{
|
||||||
case ANGLE_DEG:
|
case AngleType::Degrees:
|
||||||
if (rat_gt(*pa, rat_180, precision))
|
if (rat_gt(*pa, rat_180, precision))
|
||||||
{
|
{
|
||||||
subrat(pa, rat_180, precision);
|
subrat(pa, rat_180, precision);
|
||||||
|
@ -277,7 +277,7 @@ void tananglerat(_Inout_ PRAT* pa, ANGLE_TYPE angletype, uint32_t radix, int32_t
|
||||||
divrat(pa, rat_180, precision);
|
divrat(pa, rat_180, precision);
|
||||||
mulrat(pa, pi, precision);
|
mulrat(pa, pi, precision);
|
||||||
break;
|
break;
|
||||||
case ANGLE_GRAD:
|
case AngleType::Gradians:
|
||||||
if (rat_gt(*pa, rat_200, precision))
|
if (rat_gt(*pa, rat_200, precision))
|
||||||
{
|
{
|
||||||
subrat(pa, rat_200, precision);
|
subrat(pa, rat_200, precision);
|
||||||
|
|
|
@ -13,19 +13,19 @@ using namespace std;
|
||||||
using namespace UnitConversionManager;
|
using namespace UnitConversionManager;
|
||||||
using namespace CalcManager::NumberFormattingUtils;
|
using namespace CalcManager::NumberFormattingUtils;
|
||||||
|
|
||||||
static constexpr uint32_t EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT = 3;
|
static constexpr uint32_t EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT = 3U;
|
||||||
static constexpr uint32_t EXPECTEDSERIALIZEDUNITTOKENCOUNT = 6;
|
static constexpr uint32_t EXPECTEDSERIALIZEDUNITTOKENCOUNT = 6U;
|
||||||
static constexpr uint32_t EXPECTEDSTATEDATATOKENCOUNT = 5;
|
static constexpr uint32_t EXPECTEDSTATEDATATOKENCOUNT = 5U;
|
||||||
static constexpr uint32_t EXPECTEDMAPCOMPONENTTOKENCOUNT = 2;
|
static constexpr uint32_t EXPECTEDMAPCOMPONENTTOKENCOUNT = 2U;
|
||||||
|
|
||||||
static constexpr int32_t MAXIMUMDIGITSALLOWED = 15;
|
static constexpr uint32_t MAXIMUMDIGITSALLOWED = 15U;
|
||||||
static constexpr int32_t OPTIMALDIGITSALLOWED = 7;
|
static constexpr uint32_t OPTIMALDIGITSALLOWED = 7U;
|
||||||
|
|
||||||
static constexpr wchar_t LEFTESCAPECHAR = L'{';
|
static constexpr wchar_t LEFTESCAPECHAR = L'{';
|
||||||
static constexpr wchar_t RIGHTESCAPECHAR = L'}';
|
static constexpr wchar_t RIGHTESCAPECHAR = L'}';
|
||||||
|
|
||||||
static const double OPTIMALDECIMALALLOWED = pow(10, -1 * (OPTIMALDIGITSALLOWED - 1));
|
static const double OPTIMALDECIMALALLOWED = 1e-6; // pow(10, -1 * (OPTIMALDIGITSALLOWED - 1));
|
||||||
static const double MINIMUMDECIMALALLOWED = pow(10, -1 * (MAXIMUMDIGITSALLOWED - 1));
|
static const double MINIMUMDECIMALALLOWED = 1e-14; // pow(10, -1 * (MAXIMUMDIGITSALLOWED - 1));
|
||||||
|
|
||||||
unordered_map<wchar_t, wstring> quoteConversions;
|
unordered_map<wchar_t, wstring> quoteConversions;
|
||||||
unordered_map<wstring, wchar_t> unquoteConversions;
|
unordered_map<wstring, wchar_t> unquoteConversions;
|
||||||
|
@ -109,7 +109,7 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i
|
||||||
{
|
{
|
||||||
if (m_currentCategory.id != input.id)
|
if (m_currentCategory.id != input.id)
|
||||||
{
|
{
|
||||||
for (auto& unit : m_categoryToUnits[m_currentCategory])
|
for (auto& unit : m_categoryToUnits[m_currentCategory.id])
|
||||||
{
|
{
|
||||||
unit.isConversionSource = (unit.id == m_fromType.id);
|
unit.isConversionSource = (unit.id == m_fromType.id);
|
||||||
unit.isConversionTarget = (unit.id == m_toType.id);
|
unit.isConversionTarget = (unit.id == m_toType.id);
|
||||||
|
@ -121,7 +121,7 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newUnitList = m_categoryToUnits[input];
|
newUnitList = m_categoryToUnits[input.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeSelectedUnits();
|
InitializeSelectedUnits();
|
||||||
|
@ -149,6 +149,11 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_fromType != fromType)
|
||||||
|
{
|
||||||
|
m_switchedActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
m_fromType = fromType;
|
m_fromType = fromType;
|
||||||
m_toType = toType;
|
m_toType = toType;
|
||||||
Calculate();
|
Calculate();
|
||||||
|
@ -191,6 +196,11 @@ void UnitConverter::SwitchActive(const wstring& newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UnitConversionManager::UnitConverter::IsSwitchedActive() const
|
||||||
|
{
|
||||||
|
return m_switchedActive;
|
||||||
|
}
|
||||||
|
|
||||||
wstring UnitConverter::CategoryToString(const Category& c, wstring_view delimiter)
|
wstring UnitConverter::CategoryToString(const Category& c, wstring_view delimiter)
|
||||||
{
|
{
|
||||||
return Quote(std::to_wstring(c.id))
|
return Quote(std::to_wstring(c.id))
|
||||||
|
@ -209,7 +219,7 @@ vector<wstring> UnitConverter::StringToVector(wstring_view w, wstring_view delim
|
||||||
while (delimiterIndex != wstring_view::npos)
|
while (delimiterIndex != wstring_view::npos)
|
||||||
{
|
{
|
||||||
serializedTokens.emplace_back(w.substr(startIndex, delimiterIndex - startIndex));
|
serializedTokens.emplace_back(w.substr(startIndex, delimiterIndex - startIndex));
|
||||||
startIndex = delimiterIndex + (int)delimiter.size();
|
startIndex = delimiterIndex + static_cast<int>(delimiter.size());
|
||||||
delimiterIndex = w.find(delimiter, startIndex);
|
delimiterIndex = w.find(delimiter, startIndex);
|
||||||
}
|
}
|
||||||
if (addRemainder)
|
if (addRemainder)
|
||||||
|
@ -244,9 +254,9 @@ Unit UnitConverter::StringToUnit(wstring_view w)
|
||||||
serializedUnit.name = Unquote(tokenList[1]);
|
serializedUnit.name = Unquote(tokenList[1]);
|
||||||
serializedUnit.accessibleName = serializedUnit.name;
|
serializedUnit.accessibleName = serializedUnit.name;
|
||||||
serializedUnit.abbreviation = Unquote(tokenList[2]);
|
serializedUnit.abbreviation = Unquote(tokenList[2]);
|
||||||
serializedUnit.isConversionSource = (tokenList[3].compare(L"1") == 0);
|
serializedUnit.isConversionSource = (tokenList[3] == L"1");
|
||||||
serializedUnit.isConversionTarget = (tokenList[4].compare(L"1") == 0);
|
serializedUnit.isConversionTarget = (tokenList[4] == L"1");
|
||||||
serializedUnit.isWhimsical = (tokenList[5].compare(L"1") == 0);
|
serializedUnit.isWhimsical = (tokenList[5] == L"1");
|
||||||
return serializedUnit;
|
return serializedUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +266,7 @@ Category UnitConverter::StringToCategory(wstring_view w)
|
||||||
assert(tokenList.size() == EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT);
|
assert(tokenList.size() == EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT);
|
||||||
Category serializedCategory;
|
Category serializedCategory;
|
||||||
serializedCategory.id = wcstol(Unquote(tokenList[0]).c_str(), nullptr, 10);
|
serializedCategory.id = wcstol(Unquote(tokenList[0]).c_str(), nullptr, 10);
|
||||||
serializedCategory.supportsNegative = (tokenList[1].compare(L"1") == 0);
|
serializedCategory.supportsNegative = (tokenList[1] == L"1");
|
||||||
serializedCategory.name = Unquote(tokenList[2]);
|
serializedCategory.name = Unquote(tokenList[2]);
|
||||||
return serializedCategory;
|
return serializedCategory;
|
||||||
}
|
}
|
||||||
|
@ -283,7 +293,7 @@ void UnitConverter::RestoreUserPreferences(wstring_view userPreferences)
|
||||||
m_currentCategory = StringToCategory(outerTokens[2]);
|
m_currentCategory = StringToCategory(outerTokens[2]);
|
||||||
|
|
||||||
// Only restore from the saved units if they are valid in the current available units.
|
// Only restore from the saved units if they are valid in the current available units.
|
||||||
auto itr = m_categoryToUnits.find(m_currentCategory);
|
auto itr = m_categoryToUnits.find(m_currentCategory.id);
|
||||||
if (itr != m_categoryToUnits.end())
|
if (itr != m_categoryToUnits.end())
|
||||||
{
|
{
|
||||||
const auto& curUnits = itr->second;
|
const auto& curUnits = itr->second;
|
||||||
|
@ -559,7 +569,7 @@ future<pair<bool, wstring>> UnitConverter::RefreshCurrencyRatios()
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_future<bool> sharedLoadResult = loadDataResult.share();
|
shared_future<bool> sharedLoadResult = loadDataResult.share();
|
||||||
return async([this, currencyDataLoader, sharedLoadResult]() {
|
return async([currencyDataLoader, sharedLoadResult]() {
|
||||||
sharedLoadResult.wait();
|
sharedLoadResult.wait();
|
||||||
bool didLoad = sharedLoadResult.get();
|
bool didLoad = sharedLoadResult.get();
|
||||||
wstring timestamp;
|
wstring timestamp;
|
||||||
|
@ -618,10 +628,10 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
|
||||||
newEntry.magnitude = log10(convertedValue);
|
newEntry.magnitude = log10(convertedValue);
|
||||||
newEntry.value = convertedValue;
|
newEntry.value = convertedValue;
|
||||||
newEntry.type = cur.first;
|
newEntry.type = cur.first;
|
||||||
if (newEntry.type.isWhimsical == false)
|
if (newEntry.type.isWhimsical)
|
||||||
intermediateVector.push_back(newEntry);
|
|
||||||
else
|
|
||||||
intermediateWhimsicalVector.push_back(newEntry);
|
intermediateWhimsicalVector.push_back(newEntry);
|
||||||
|
else
|
||||||
|
intermediateVector.push_back(newEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,15 +653,15 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
|
||||||
wstring roundedString;
|
wstring roundedString;
|
||||||
if (abs(entry.value) < 100)
|
if (abs(entry.value) < 100)
|
||||||
{
|
{
|
||||||
roundedString = RoundSignificantDigits(entry.value, 2);
|
roundedString = RoundSignificantDigits(entry.value, 2U);
|
||||||
}
|
}
|
||||||
else if (abs(entry.value) < 1000)
|
else if (abs(entry.value) < 1000)
|
||||||
{
|
{
|
||||||
roundedString = RoundSignificantDigits(entry.value, 1);
|
roundedString = RoundSignificantDigits(entry.value, 1U);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
roundedString = RoundSignificantDigits(entry.value, 0);
|
roundedString = RoundSignificantDigits(entry.value, 0U);
|
||||||
}
|
}
|
||||||
if (stod(roundedString) != 0.0 || m_currentCategory.supportsNegative)
|
if (stod(roundedString) != 0.0 || m_currentCategory.supportsNegative)
|
||||||
{
|
{
|
||||||
|
@ -681,15 +691,15 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
|
||||||
wstring roundedString;
|
wstring roundedString;
|
||||||
if (abs(entry.value) < 100)
|
if (abs(entry.value) < 100)
|
||||||
{
|
{
|
||||||
roundedString = RoundSignificantDigits(entry.value, 2);
|
roundedString = RoundSignificantDigits(entry.value, 2U);
|
||||||
}
|
}
|
||||||
else if (abs(entry.value) < 1000)
|
else if (abs(entry.value) < 1000)
|
||||||
{
|
{
|
||||||
roundedString = RoundSignificantDigits(entry.value, 1);
|
roundedString = RoundSignificantDigits(entry.value, 1U);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
roundedString = RoundSignificantDigits(entry.value, 0);
|
roundedString = RoundSignificantDigits(entry.value, 0U);
|
||||||
}
|
}
|
||||||
|
|
||||||
// How to work out which is the best whimsical value to add to the vector?
|
// How to work out which is the best whimsical value to add to the vector?
|
||||||
|
@ -713,10 +723,8 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UnitConverter::ResetCategoriesAndRatios()
|
void UnitConverter::ResetCategoriesAndRatios()
|
||||||
{
|
{
|
||||||
m_categories = m_dataLoader->LoadOrderedCategories();
|
|
||||||
|
|
||||||
m_switchedActive = false;
|
m_switchedActive = false;
|
||||||
|
m_categories = m_dataLoader->GetOrderedCategories();
|
||||||
if (m_categories.empty())
|
if (m_categories.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -738,8 +746,8 @@ void UnitConverter::ResetCategoriesAndRatios()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Unit> units = activeDataLoader->LoadOrderedUnits(category);
|
vector<Unit> units = activeDataLoader->GetOrderedUnits(category);
|
||||||
m_categoryToUnits[category] = units;
|
m_categoryToUnits[category.id] = units;
|
||||||
|
|
||||||
// Just because the units are empty, doesn't mean the user can't select this category,
|
// Just because the units are empty, doesn't mean the user can't select this category,
|
||||||
// we just want to make sure we don't let an unready category be the default.
|
// we just want to make sure we don't let an unready category be the default.
|
||||||
|
@ -789,7 +797,7 @@ void UnitConverter::InitializeSelectedUnits()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto itr = m_categoryToUnits.find(m_currentCategory);
|
auto itr = m_categoryToUnits.find(m_currentCategory.id);
|
||||||
if (itr == m_categoryToUnits.end())
|
if (itr == m_categoryToUnits.end())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -800,8 +808,8 @@ void UnitConverter::InitializeSelectedUnits()
|
||||||
{
|
{
|
||||||
// Units may already have been initialized through UnitConverter::RestoreUserPreferences().
|
// Units may already have been initialized through UnitConverter::RestoreUserPreferences().
|
||||||
// Check if they have been, and if so, do not override restored units.
|
// Check if they have been, and if so, do not override restored units.
|
||||||
bool isFromUnitValid = m_fromType != EMPTY_UNIT && find(curUnits.begin(), curUnits.end(), m_fromType) != curUnits.end();
|
const bool isFromUnitValid = m_fromType != EMPTY_UNIT && find(curUnits.begin(), curUnits.end(), m_fromType) != curUnits.end();
|
||||||
bool isToUnitValid = m_toType != EMPTY_UNIT && find(curUnits.begin(), curUnits.end(), m_toType) != curUnits.end();
|
const bool isToUnitValid = m_toType != EMPTY_UNIT && find(curUnits.begin(), curUnits.end(), m_toType) != curUnits.end();
|
||||||
|
|
||||||
if (isFromUnitValid && isToUnitValid)
|
if (isFromUnitValid && isToUnitValid)
|
||||||
{
|
{
|
||||||
|
@ -877,9 +885,9 @@ void UnitConverter::Calculate()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double currentValue = stod(m_currentDisplay);
|
double currentValue = stod(m_currentDisplay);
|
||||||
double returnValue = Convert(currentValue, conversionTable[m_toType]);
|
const double returnValue = Convert(currentValue, conversionTable[m_toType]);
|
||||||
|
|
||||||
auto isCurrencyConverter = m_currencyDataLoader != nullptr && m_currencyDataLoader->SupportsCategory(this->m_currentCategory);
|
const auto isCurrencyConverter = m_currencyDataLoader != nullptr && m_currencyDataLoader->SupportsCategory(this->m_currentCategory);
|
||||||
if (isCurrencyConverter)
|
if (isCurrencyConverter)
|
||||||
{
|
{
|
||||||
// We don't need to trim the value when it's a currency.
|
// We don't need to trim the value when it's a currency.
|
||||||
|
@ -888,15 +896,15 @@ void UnitConverter::Calculate()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int numPreDecimal = GetNumberDigitsWholeNumberPart(returnValue);
|
const unsigned int numPreDecimal = GetNumberDigitsWholeNumberPart(returnValue);
|
||||||
if (numPreDecimal > MAXIMUMDIGITSALLOWED || (returnValue != 0 && abs(returnValue) < MINIMUMDECIMALALLOWED))
|
if (numPreDecimal > MAXIMUMDIGITSALLOWED || (returnValue != 0 && abs(returnValue) < MINIMUMDECIMALALLOWED))
|
||||||
{
|
{
|
||||||
m_returnDisplay = ToScientificNumber(returnValue);
|
m_returnDisplay = ToScientificNumber(returnValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int currentNumberSignificantDigits = GetNumberDigits(m_currentDisplay);
|
const unsigned int currentNumberSignificantDigits = GetNumberDigits(m_currentDisplay);
|
||||||
int precision = 0;
|
unsigned int precision;
|
||||||
if (abs(returnValue) < OPTIMALDECIMALALLOWED)
|
if (abs(returnValue) < OPTIMALDECIMALALLOWED)
|
||||||
{
|
{
|
||||||
precision = MAXIMUMDIGITSALLOWED;
|
precision = MAXIMUMDIGITSALLOWED;
|
||||||
|
@ -905,7 +913,8 @@ void UnitConverter::Calculate()
|
||||||
{
|
{
|
||||||
// Fewer digits are needed following the decimal if the number is large,
|
// 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.
|
// 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);
|
auto numberDigits = max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits));
|
||||||
|
precision = numberDigits > numPreDecimal ? numberDigits - numPreDecimal : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_returnDisplay = RoundSignificantDigits(returnValue, precision);
|
m_returnDisplay = RoundSignificantDigits(returnValue, precision);
|
||||||
|
|
|
@ -18,11 +18,11 @@ namespace UnitConversionManager
|
||||||
Unit()
|
Unit()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Unit(int id, std::wstring name, std::wstring abbreviation, bool isConversionSource, bool isConversionTarget, bool isWhimsical)
|
Unit(int id, std::wstring_view name, std::wstring abbreviation, bool isConversionSource, bool isConversionTarget, bool isWhimsical)
|
||||||
: id(id)
|
: id(id)
|
||||||
, name(name)
|
, name(name)
|
||||||
, accessibleName(name)
|
, accessibleName(name)
|
||||||
, abbreviation(abbreviation)
|
, abbreviation(std::move(abbreviation))
|
||||||
, isConversionSource(isConversionSource)
|
, isConversionSource(isConversionSource)
|
||||||
, isConversionTarget(isConversionTarget)
|
, isConversionTarget(isConversionTarget)
|
||||||
, isWhimsical(isWhimsical)
|
, isWhimsical(isWhimsical)
|
||||||
|
@ -31,23 +31,26 @@ namespace UnitConversionManager
|
||||||
|
|
||||||
Unit(
|
Unit(
|
||||||
int id,
|
int id,
|
||||||
std::wstring currencyName,
|
std::wstring_view currencyName,
|
||||||
std::wstring countryName,
|
std::wstring_view countryName,
|
||||||
std::wstring abbreviation,
|
std::wstring abbreviation,
|
||||||
bool isRtlLanguage,
|
bool isRtlLanguage,
|
||||||
bool isConversionSource,
|
bool isConversionSource,
|
||||||
bool isConversionTarget)
|
bool isConversionTarget)
|
||||||
: id(id)
|
: id(id)
|
||||||
, abbreviation(abbreviation)
|
, abbreviation(std::move(abbreviation))
|
||||||
, isConversionSource(isConversionSource)
|
, isConversionSource(isConversionSource)
|
||||||
, isConversionTarget(isConversionTarget)
|
, isConversionTarget(isConversionTarget)
|
||||||
, isWhimsical(false)
|
, isWhimsical(false)
|
||||||
{
|
{
|
||||||
std::wstring nameValue1 = isRtlLanguage ? currencyName : countryName;
|
auto nameValue1 = isRtlLanguage ? currencyName : countryName;
|
||||||
std::wstring nameValue2 = isRtlLanguage ? countryName : currencyName;
|
auto nameValue2 = isRtlLanguage ? countryName : currencyName;
|
||||||
|
|
||||||
name = nameValue1 + L" - " + nameValue2;
|
name = nameValue1;
|
||||||
accessibleName = nameValue1 + L" " + nameValue2;
|
name.append(L" - ").append(nameValue2);
|
||||||
|
|
||||||
|
accessibleName = nameValue1;
|
||||||
|
accessibleName.append(1, L' ').append(nameValue2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
|
@ -84,7 +87,7 @@ namespace UnitConversionManager
|
||||||
|
|
||||||
Category(int id, std::wstring name, bool supportsNegative)
|
Category(int id, std::wstring name, bool supportsNegative)
|
||||||
: id(id)
|
: id(id)
|
||||||
, name(name)
|
, name(std::move(name))
|
||||||
, supportsNegative(supportsNegative)
|
, supportsNegative(supportsNegative)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -113,15 +116,6 @@ namespace UnitConversionManager
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CategoryHash
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
size_t operator()(const Category& x) const
|
|
||||||
{
|
|
||||||
return x.id;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SuggestedValueIntermediate
|
struct SuggestedValueIntermediate
|
||||||
{
|
{
|
||||||
double magnitude;
|
double magnitude;
|
||||||
|
@ -168,7 +162,7 @@ namespace UnitConversionManager
|
||||||
std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash>,
|
std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash>,
|
||||||
UnitConversionManager::UnitHash>
|
UnitConversionManager::UnitHash>
|
||||||
UnitToUnitToConversionDataMap;
|
UnitToUnitToConversionDataMap;
|
||||||
typedef std::unordered_map<UnitConversionManager::Category, std::vector<UnitConversionManager::Unit>, UnitConversionManager::CategoryHash>
|
typedef std::unordered_map<int, std::vector<UnitConversionManager::Unit>>
|
||||||
CategoryToUnitVectorMap;
|
CategoryToUnitVectorMap;
|
||||||
|
|
||||||
class IViewModelCurrencyCallback
|
class IViewModelCurrencyCallback
|
||||||
|
@ -187,8 +181,8 @@ namespace UnitConversionManager
|
||||||
public:
|
public:
|
||||||
virtual ~IConverterDataLoader(){};
|
virtual ~IConverterDataLoader(){};
|
||||||
virtual void LoadData() = 0; // prepare data if necessary before calling other functions
|
virtual void LoadData() = 0; // prepare data if necessary before calling other functions
|
||||||
virtual std::vector<Category> LoadOrderedCategories() = 0;
|
virtual std::vector<Category> GetOrderedCategories() = 0;
|
||||||
virtual std::vector<Unit> LoadOrderedUnits(const Category& c) = 0;
|
virtual std::vector<Unit> GetOrderedUnits(const Category& c) = 0;
|
||||||
virtual std::unordered_map<Unit, ConversionData, UnitHash> LoadOrderedRatios(const Unit& u) = 0;
|
virtual std::unordered_map<Unit, ConversionData, UnitHash> LoadOrderedRatios(const Unit& u) = 0;
|
||||||
virtual bool SupportsCategory(const Category& target) = 0;
|
virtual bool SupportsCategory(const Category& target) = 0;
|
||||||
};
|
};
|
||||||
|
@ -229,6 +223,7 @@ namespace UnitConversionManager
|
||||||
virtual Category GetCurrentCategory() = 0;
|
virtual Category GetCurrentCategory() = 0;
|
||||||
virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0;
|
virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0;
|
||||||
virtual void SwitchActive(const std::wstring& newValue) = 0;
|
virtual void SwitchActive(const std::wstring& newValue) = 0;
|
||||||
|
virtual bool IsSwitchedActive() const = 0;
|
||||||
virtual std::wstring SaveUserPreferences() = 0;
|
virtual std::wstring SaveUserPreferences() = 0;
|
||||||
virtual void RestoreUserPreferences(_In_ std::wstring_view userPreferences) = 0;
|
virtual void RestoreUserPreferences(_In_ std::wstring_view userPreferences) = 0;
|
||||||
virtual void SendCommand(Command command) = 0;
|
virtual void SendCommand(Command command) = 0;
|
||||||
|
@ -252,6 +247,7 @@ namespace UnitConversionManager
|
||||||
Category GetCurrentCategory() override;
|
Category GetCurrentCategory() override;
|
||||||
void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override;
|
void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override;
|
||||||
void SwitchActive(const std::wstring& newValue) override;
|
void SwitchActive(const std::wstring& newValue) override;
|
||||||
|
bool IsSwitchedActive() const override;
|
||||||
std::wstring SaveUserPreferences() override;
|
std::wstring SaveUserPreferences() override;
|
||||||
void RestoreUserPreferences(std::wstring_view userPreference) override;
|
void RestoreUserPreferences(std::wstring_view userPreference) override;
|
||||||
void SendCommand(Command command) override;
|
void SendCommand(Command command) override;
|
||||||
|
|
|
@ -21,6 +21,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <winerror.h>
|
#include <winerror.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace
|
||||||
ApplicationViewModel::ApplicationViewModel()
|
ApplicationViewModel::ApplicationViewModel()
|
||||||
: m_CalculatorViewModel(nullptr)
|
: m_CalculatorViewModel(nullptr)
|
||||||
, m_DateCalcViewModel(nullptr)
|
, m_DateCalcViewModel(nullptr)
|
||||||
|
, m_GraphingCalcViewModel(nullptr)
|
||||||
, m_ConverterViewModel(nullptr)
|
, m_ConverterViewModel(nullptr)
|
||||||
, m_PreviousMode(ViewMode::None)
|
, m_PreviousMode(ViewMode::None)
|
||||||
, m_mode(ViewMode::None)
|
, m_mode(ViewMode::None)
|
||||||
|
@ -74,7 +75,7 @@ void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup ^>
|
||||||
|
|
||||||
void ApplicationViewModel::Initialize(ViewMode mode)
|
void ApplicationViewModel::Initialize(ViewMode mode)
|
||||||
{
|
{
|
||||||
if (!NavCategory::IsValidViewMode(mode))
|
if (!NavCategory::IsValidViewMode(mode) || !NavCategory::IsViewModeEnabled(mode))
|
||||||
{
|
{
|
||||||
mode = ViewMode::Standard;
|
mode = ViewMode::Standard;
|
||||||
}
|
}
|
||||||
|
@ -132,6 +133,13 @@ void ApplicationViewModel::OnModeChanged()
|
||||||
}
|
}
|
||||||
m_CalculatorViewModel->SetCalculatorType(m_mode);
|
m_CalculatorViewModel->SetCalculatorType(m_mode);
|
||||||
}
|
}
|
||||||
|
else if (NavCategory::IsGraphingCalculatorViewMode(m_mode))
|
||||||
|
{
|
||||||
|
if (!m_GraphingCalcViewModel)
|
||||||
|
{
|
||||||
|
m_GraphingCalcViewModel = ref new GraphingCalculatorViewModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (NavCategory::IsDateCalculatorViewMode(m_mode))
|
else if (NavCategory::IsDateCalculatorViewMode(m_mode))
|
||||||
{
|
{
|
||||||
if (!m_DateCalcViewModel)
|
if (!m_DateCalcViewModel)
|
||||||
|
@ -182,7 +190,7 @@ void ApplicationViewModel::OnCopyCommand(Object ^ parameter)
|
||||||
{
|
{
|
||||||
DateCalcViewModel->OnCopyCommand(parameter);
|
DateCalcViewModel->OnCopyCommand(parameter);
|
||||||
}
|
}
|
||||||
else
|
else if (NavCategory::IsCalculatorViewMode(m_mode))
|
||||||
{
|
{
|
||||||
CalculatorViewModel->OnCopyCommand(parameter);
|
CalculatorViewModel->OnCopyCommand(parameter);
|
||||||
}
|
}
|
||||||
|
@ -223,7 +231,6 @@ task<void> ApplicationViewModel::HandleToggleAlwaysOnTop(float width, float heig
|
||||||
localSettings->Values->Insert(HeightLocalSettings, height);
|
localSettings->Values->Insert(HeightLocalSettings, height);
|
||||||
|
|
||||||
bool success = co_await ApplicationView::GetForCurrentView()->TryEnterViewModeAsync(ApplicationViewMode::Default);
|
bool success = co_await ApplicationView::GetForCurrentView()->TryEnterViewModeAsync(ApplicationViewMode::Default);
|
||||||
CalculatorViewModel->AreHistoryShortcutsEnabled = success;
|
|
||||||
CalculatorViewModel->HistoryVM->AreHistoryShortcutsEnabled = success;
|
CalculatorViewModel->HistoryVM->AreHistoryShortcutsEnabled = success;
|
||||||
CalculatorViewModel->IsAlwaysOnTop = !success;
|
CalculatorViewModel->IsAlwaysOnTop = !success;
|
||||||
IsAlwaysOnTop = !success;
|
IsAlwaysOnTop = !success;
|
||||||
|
@ -252,7 +259,6 @@ task<void> ApplicationViewModel::HandleToggleAlwaysOnTop(float width, float heig
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = co_await ApplicationView::GetForCurrentView()->TryEnterViewModeAsync(ApplicationViewMode::CompactOverlay, compactOptions);
|
bool success = co_await ApplicationView::GetForCurrentView()->TryEnterViewModeAsync(ApplicationViewMode::CompactOverlay, compactOptions);
|
||||||
CalculatorViewModel->AreHistoryShortcutsEnabled = !success;
|
|
||||||
CalculatorViewModel->HistoryVM->AreHistoryShortcutsEnabled = !success;
|
CalculatorViewModel->HistoryVM->AreHistoryShortcutsEnabled = !success;
|
||||||
CalculatorViewModel->IsAlwaysOnTop = success;
|
CalculatorViewModel->IsAlwaysOnTop = success;
|
||||||
IsAlwaysOnTop = success;
|
IsAlwaysOnTop = success;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "StandardCalculatorViewModel.h"
|
#include "StandardCalculatorViewModel.h"
|
||||||
#include "DateCalculatorViewModel.h"
|
#include "DateCalculatorViewModel.h"
|
||||||
|
#include "GraphingCalculator/GraphingCalculatorViewModel.h"
|
||||||
#include "UnitConverterViewModel.h"
|
#include "UnitConverterViewModel.h"
|
||||||
|
|
||||||
namespace CalculatorApp
|
namespace CalculatorApp
|
||||||
|
@ -21,6 +22,7 @@ namespace CalculatorApp
|
||||||
OBSERVABLE_OBJECT();
|
OBSERVABLE_OBJECT();
|
||||||
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel);
|
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel);
|
||||||
OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel ^, DateCalcViewModel);
|
OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel ^, DateCalcViewModel);
|
||||||
|
OBSERVABLE_PROPERTY_RW(GraphingCalculatorViewModel ^, GraphingCalcViewModel);
|
||||||
OBSERVABLE_PROPERTY_RW(UnitConverterViewModel ^, ConverterViewModel);
|
OBSERVABLE_PROPERTY_RW(UnitConverterViewModel ^, ConverterViewModel);
|
||||||
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode);
|
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode);
|
||||||
OBSERVABLE_PROPERTY_R(bool, IsAlwaysOnTop);
|
OBSERVABLE_PROPERTY_R(bool, IsAlwaysOnTop);
|
||||||
|
|
|
@ -122,29 +122,9 @@
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup />
|
<PropertyGroup />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup>
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<GenerateManifest>false</GenerateManifest>
|
<GenerateManifest>false</GenerateManifest>
|
||||||
|
<GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
|
@ -313,16 +293,13 @@
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="ApplicationViewModel.h" />
|
<ClInclude Include="ApplicationViewModel.h" />
|
||||||
<ClInclude Include="Common\AlwaysSelectedCollectionView.h" />
|
|
||||||
<ClInclude Include="Common\AppResourceProvider.h" />
|
<ClInclude Include="Common\AppResourceProvider.h" />
|
||||||
<ClInclude Include="Common\Automation\NarratorAnnouncement.h" />
|
<ClInclude Include="Common\Automation\NarratorAnnouncement.h" />
|
||||||
<ClInclude Include="Common\Automation\NarratorNotifier.h" />
|
<ClInclude Include="Common\Automation\NarratorNotifier.h" />
|
||||||
<ClInclude Include="Common\BindableBase.h" />
|
|
||||||
<ClInclude Include="Common\BitLength.h" />
|
<ClInclude Include="Common\BitLength.h" />
|
||||||
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h" />
|
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h" />
|
||||||
<ClInclude Include="Common\CalculatorButtonUser.h" />
|
<ClInclude Include="Common\CalculatorButtonUser.h" />
|
||||||
<ClInclude Include="Common\CalculatorDisplay.h" />
|
<ClInclude Include="Common\CalculatorDisplay.h" />
|
||||||
<ClInclude Include="Common\ConversionResultTaskHelper.h" />
|
|
||||||
<ClInclude Include="Common\CopyPasteManager.h" />
|
<ClInclude Include="Common\CopyPasteManager.h" />
|
||||||
<ClInclude Include="Common\DateCalculator.h" />
|
<ClInclude Include="Common\DateCalculator.h" />
|
||||||
<ClInclude Include="Common\DelegateCommand.h" />
|
<ClInclude Include="Common\DelegateCommand.h" />
|
||||||
|
@ -330,7 +307,6 @@
|
||||||
<ClInclude Include="Common\EngineResourceProvider.h" />
|
<ClInclude Include="Common\EngineResourceProvider.h" />
|
||||||
<ClInclude Include="Common\ExpressionCommandDeserializer.h" />
|
<ClInclude Include="Common\ExpressionCommandDeserializer.h" />
|
||||||
<ClInclude Include="Common\ExpressionCommandSerializer.h" />
|
<ClInclude Include="Common\ExpressionCommandSerializer.h" />
|
||||||
<ClInclude Include="Common\KeyboardShortcutManager.h" />
|
|
||||||
<ClInclude Include="Common\LocalizationService.h" />
|
<ClInclude Include="Common\LocalizationService.h" />
|
||||||
<ClInclude Include="Common\LocalizationSettings.h" />
|
<ClInclude Include="Common\LocalizationSettings.h" />
|
||||||
<ClInclude Include="Common\LocalizationStringUtil.h" />
|
<ClInclude Include="Common\LocalizationStringUtil.h" />
|
||||||
|
@ -338,16 +314,19 @@
|
||||||
<ClInclude Include="Common\NavCategory.h" />
|
<ClInclude Include="Common\NavCategory.h" />
|
||||||
<ClInclude Include="Common\NetworkManager.h" />
|
<ClInclude Include="Common\NetworkManager.h" />
|
||||||
<ClInclude Include="Common\NumberBase.h" />
|
<ClInclude Include="Common\NumberBase.h" />
|
||||||
<ClInclude Include="Common\TraceActivity.h" />
|
|
||||||
<ClInclude Include="Common\TraceLogger.h" />
|
<ClInclude Include="Common\TraceLogger.h" />
|
||||||
<ClInclude Include="Common\Utils.h" />
|
<ClInclude Include="Common\Utils.h" />
|
||||||
<ClInclude Include="Common\ValidatingConverters.h" />
|
|
||||||
<ClInclude Include="DataLoaders\CurrencyDataLoader.h" />
|
<ClInclude Include="DataLoaders\CurrencyDataLoader.h" />
|
||||||
<ClInclude Include="DataLoaders\CurrencyHttpClient.h" />
|
<ClInclude Include="DataLoaders\CurrencyHttpClient.h" />
|
||||||
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h" />
|
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h" />
|
||||||
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h" />
|
<ClInclude Include="DataLoaders\UnitConverterDataConstants.h" />
|
||||||
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h" />
|
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h" />
|
||||||
<ClInclude Include="DateCalculatorViewModel.h" />
|
<ClInclude Include="DateCalculatorViewModel.h" />
|
||||||
|
<ClInclude Include="GraphingCalculatorEnums.h" />
|
||||||
|
<ClInclude Include="GraphingCalculator\EquationViewModel.h" />
|
||||||
|
<ClInclude Include="GraphingCalculator\GraphingCalculatorViewModel.h" />
|
||||||
|
<ClInclude Include="GraphingCalculator\VariableViewModel.h" />
|
||||||
|
<ClInclude Include="GraphingCalculator\GraphingSettingsViewModel.h" />
|
||||||
<ClInclude Include="HistoryItemViewModel.h" />
|
<ClInclude Include="HistoryItemViewModel.h" />
|
||||||
<ClInclude Include="HistoryViewModel.h" />
|
<ClInclude Include="HistoryViewModel.h" />
|
||||||
<ClInclude Include="MemoryItemViewModel.h" />
|
<ClInclude Include="MemoryItemViewModel.h" />
|
||||||
|
@ -361,16 +340,13 @@
|
||||||
<ClCompile Include="Common\AppResourceProvider.cpp" />
|
<ClCompile Include="Common\AppResourceProvider.cpp" />
|
||||||
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp" />
|
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp" />
|
||||||
<ClCompile Include="Common\Automation\NarratorNotifier.cpp" />
|
<ClCompile Include="Common\Automation\NarratorNotifier.cpp" />
|
||||||
<ClCompile Include="Common\BindableBase.cpp" />
|
|
||||||
<ClCompile Include="Common\CalculatorButtonPressedEventArgs.cpp" />
|
<ClCompile Include="Common\CalculatorButtonPressedEventArgs.cpp" />
|
||||||
<ClCompile Include="Common\CalculatorDisplay.cpp" />
|
<ClCompile Include="Common\CalculatorDisplay.cpp" />
|
||||||
<ClCompile Include="Common\ConversionResultTaskHelper.cpp" />
|
|
||||||
<ClCompile Include="Common\CopyPasteManager.cpp" />
|
<ClCompile Include="Common\CopyPasteManager.cpp" />
|
||||||
<ClCompile Include="Common\DateCalculator.cpp" />
|
<ClCompile Include="Common\DateCalculator.cpp" />
|
||||||
<ClCompile Include="Common\EngineResourceProvider.cpp" />
|
<ClCompile Include="Common\EngineResourceProvider.cpp" />
|
||||||
<ClCompile Include="Common\ExpressionCommandDeserializer.cpp" />
|
<ClCompile Include="Common\ExpressionCommandDeserializer.cpp" />
|
||||||
<ClCompile Include="Common\ExpressionCommandSerializer.cpp" />
|
<ClCompile Include="Common\ExpressionCommandSerializer.cpp" />
|
||||||
<ClCompile Include="Common\KeyboardShortcutManager.cpp" />
|
|
||||||
<ClCompile Include="Common\LocalizationService.cpp" />
|
<ClCompile Include="Common\LocalizationService.cpp" />
|
||||||
<ClCompile Include="Common\NavCategory.cpp" />
|
<ClCompile Include="Common\NavCategory.cpp" />
|
||||||
<ClCompile Include="Common\NetworkManager.cpp" />
|
<ClCompile Include="Common\NetworkManager.cpp" />
|
||||||
|
@ -380,6 +356,9 @@
|
||||||
<ClCompile Include="DataLoaders\CurrencyHttpClient.cpp" />
|
<ClCompile Include="DataLoaders\CurrencyHttpClient.cpp" />
|
||||||
<ClCompile Include="DataLoaders\UnitConverterDataLoader.cpp" />
|
<ClCompile Include="DataLoaders\UnitConverterDataLoader.cpp" />
|
||||||
<ClCompile Include="DateCalculatorViewModel.cpp" />
|
<ClCompile Include="DateCalculatorViewModel.cpp" />
|
||||||
|
<ClCompile Include="GraphingCalculator\EquationViewModel.cpp" />
|
||||||
|
<ClCompile Include="GraphingCalculator\GraphingCalculatorViewModel.cpp" />
|
||||||
|
<ClCompile Include="GraphingCalculator\GraphingSettingsViewModel.cpp" />
|
||||||
<ClCompile Include="HistoryItemViewModel.cpp" />
|
<ClCompile Include="HistoryItemViewModel.cpp" />
|
||||||
<ClCompile Include="HistoryViewModel.cpp" />
|
<ClCompile Include="HistoryViewModel.cpp" />
|
||||||
<ClCompile Include="MemoryItemViewModel.cpp" />
|
<ClCompile Include="MemoryItemViewModel.cpp" />
|
||||||
|
@ -400,6 +379,12 @@
|
||||||
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
|
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
|
||||||
<Project>{311e866d-8b93-4609-a691-265941fee101}</Project>
|
<Project>{311e866d-8b93-4609-a691-265941fee101}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\GraphControl\GraphControl.vcxproj">
|
||||||
|
<Project>{e727a92b-f149-492c-8117-c039a298719b}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\TraceLogging\TraceLogging.vcxproj">
|
||||||
|
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemDefinitionGroup Condition="!Exists('DataLoaders\DataLoaderConstants.h')">
|
<ItemDefinitionGroup Condition="!Exists('DataLoaders\DataLoaderConstants.h')">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
|
@ -420,16 +405,7 @@
|
||||||
</Choose>
|
</Choose>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DataLoaders\DefaultFromToCurrency.json" />
|
<None Include="DataLoaders\DefaultFromToCurrency.json" />
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets" />
|
||||||
<Import Project="..\..\packages\Microsoft.UI.Xaml.2.2.190830001\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\packages\Microsoft.UI.Xaml.2.2.190830001\build\native\Microsoft.UI.Xaml.targets')" />
|
|
||||||
</ImportGroup>
|
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Error Condition="!Exists('..\..\packages\Microsoft.UI.Xaml.2.2.190830001\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.UI.Xaml.2.2.190830001\build\native\Microsoft.UI.Xaml.targets'))" />
|
|
||||||
</Target>
|
|
||||||
</Project>
|
</Project>
|
|
@ -10,6 +10,9 @@
|
||||||
<Filter Include="DataLoaders">
|
<Filter Include="DataLoaders">
|
||||||
<UniqueIdentifier>{0184f727-b8aa-4af8-a699-63f1b56e7853}</UniqueIdentifier>
|
<UniqueIdentifier>{0184f727-b8aa-4af8-a699-63f1b56e7853}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="GraphingCalculator">
|
||||||
|
<UniqueIdentifier>{cf7dca32-9727-4f98-83c3-1c0ca7dd1e0c}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="pch.cpp" />
|
<ClCompile Include="pch.cpp" />
|
||||||
|
@ -23,18 +26,12 @@
|
||||||
<ClCompile Include="Common\AppResourceProvider.cpp">
|
<ClCompile Include="Common\AppResourceProvider.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Common\BindableBase.cpp">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Common\CalculatorButtonPressedEventArgs.cpp">
|
<ClCompile Include="Common\CalculatorButtonPressedEventArgs.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Common\CalculatorDisplay.cpp">
|
<ClCompile Include="Common\CalculatorDisplay.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Common\ConversionResultTaskHelper.cpp">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Common\CopyPasteManager.cpp">
|
<ClCompile Include="Common\CopyPasteManager.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -50,9 +47,6 @@
|
||||||
<ClCompile Include="Common\ExpressionCommandSerializer.cpp">
|
<ClCompile Include="Common\ExpressionCommandSerializer.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Common\KeyboardShortcutManager.cpp">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Common\LocalizationService.cpp">
|
<ClCompile Include="Common\LocalizationService.cpp">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -80,9 +74,18 @@
|
||||||
<ClCompile Include="DataLoaders\UnitConverterDataLoader.cpp">
|
<ClCompile Include="DataLoaders\UnitConverterDataLoader.cpp">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="GraphingCalculator\EquationViewModel.cpp">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="GraphingCalculator\GraphingCalculatorViewModel.cpp">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp">
|
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp">
|
||||||
<Filter>Common\Automation</Filter>
|
<Filter>Common\Automation</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="GraphingCalculator\GraphingSettingsViewModel.cpp">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
|
@ -94,15 +97,9 @@
|
||||||
<ClInclude Include="MemoryItemViewModel.h" />
|
<ClInclude Include="MemoryItemViewModel.h" />
|
||||||
<ClInclude Include="StandardCalculatorViewModel.h" />
|
<ClInclude Include="StandardCalculatorViewModel.h" />
|
||||||
<ClInclude Include="UnitConverterViewModel.h" />
|
<ClInclude Include="UnitConverterViewModel.h" />
|
||||||
<ClInclude Include="Common\AlwaysSelectedCollectionView.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Common\AppResourceProvider.h">
|
<ClInclude Include="Common\AppResourceProvider.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\BindableBase.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h">
|
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -112,18 +109,12 @@
|
||||||
<ClInclude Include="Common\CalculatorDisplay.h">
|
<ClInclude Include="Common\CalculatorDisplay.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\ConversionResultTaskHelper.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Common\CopyPasteManager.h">
|
<ClInclude Include="Common\CopyPasteManager.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\DateCalculator.h">
|
<ClInclude Include="Common\DateCalculator.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\DelegateCommand.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Common\DisplayExpressionToken.h">
|
<ClInclude Include="Common\DisplayExpressionToken.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -136,9 +127,6 @@
|
||||||
<ClInclude Include="Common\ExpressionCommandSerializer.h">
|
<ClInclude Include="Common\ExpressionCommandSerializer.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\KeyboardShortcutManager.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Common\LocalizationService.h">
|
<ClInclude Include="Common\LocalizationService.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -163,9 +151,6 @@
|
||||||
<ClInclude Include="Common\Utils.h">
|
<ClInclude Include="Common\Utils.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\ValidatingConverters.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Common\Automation\NarratorNotifier.h">
|
<ClInclude Include="Common\Automation\NarratorNotifier.h">
|
||||||
<Filter>Common\Automation</Filter>
|
<Filter>Common\Automation</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -184,9 +169,6 @@
|
||||||
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h">
|
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Common\TraceActivity.h">
|
|
||||||
<Filter>Common</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DataLoaders\DataLoaderMockConstants.h">
|
<ClInclude Include="DataLoaders\DataLoaderMockConstants.h">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -199,12 +181,29 @@
|
||||||
<ClInclude Include="Common\NumberBase.h">
|
<ClInclude Include="Common\NumberBase.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="GraphingCalculator\EquationViewModel.h">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GraphingCalculator\GraphingCalculatorViewModel.h">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GraphingCalculatorEnums.h">
|
||||||
|
<Filter>Common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GraphingCalculator\VariableViewModel.h">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GraphingCalculator\GraphingSettingsViewModel.h">
|
||||||
|
<Filter>GraphingCalculator</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Common\DelegateCommand.h">
|
||||||
|
<Filter>Common</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DataLoaders\DefaultFromToCurrency.json">
|
<None Include="DataLoaders\DefaultFromToCurrency.json">
|
||||||
<Filter>DataLoaders</Filter>
|
<Filter>DataLoaders</Filter>
|
||||||
</None>
|
</None>
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Include="$(MSBuildThisFileDirectory)DensityStyles\Compact.xaml" />
|
<Page Include="$(MSBuildThisFileDirectory)DensityStyles\Compact.xaml" />
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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);
|
||||||
|
};
|
||||||
|
}
|
42
src/CalcViewModel/Common/Automation/LiveRegionHost.cpp
Normal file
42
src/CalcViewModel/Common/Automation/LiveRegionHost.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
33
src/CalcViewModel/Common/Automation/LiveRegionHost.h
Normal file
33
src/CalcViewModel/Common/Automation/LiveRegionHost.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -18,11 +18,18 @@ namespace CalculatorApp::Common::Automation
|
||||||
StringReference MemoryItemChanged(L"MemorySlotChanged");
|
StringReference MemoryItemChanged(L"MemorySlotChanged");
|
||||||
StringReference MemoryItemAdded(L"MemorySlotAdded");
|
StringReference MemoryItemAdded(L"MemorySlotAdded");
|
||||||
StringReference HistoryCleared(L"HistoryCleared");
|
StringReference HistoryCleared(L"HistoryCleared");
|
||||||
|
StringReference HistorySlotCleared(L"HistorySlotCleared");
|
||||||
StringReference CategoryNameChanged(L"CategoryNameChanged");
|
StringReference CategoryNameChanged(L"CategoryNameChanged");
|
||||||
StringReference UpdateCurrencyRates(L"UpdateCurrencyRates");
|
StringReference UpdateCurrencyRates(L"UpdateCurrencyRates");
|
||||||
StringReference DisplayCopied(L"DisplayCopied");
|
StringReference DisplayCopied(L"DisplayCopied");
|
||||||
StringReference OpenParenthesisCountChanged(L"OpenParenthesisCountChanged");
|
StringReference OpenParenthesisCountChanged(L"OpenParenthesisCountChanged");
|
||||||
StringReference NoParenthesisAdded(L"NoParenthesisAdded");
|
StringReference NoParenthesisAdded(L"NoParenthesisAdded");
|
||||||
|
StringReference GraphModeChanged(L"GraphModeChanged");
|
||||||
|
StringReference GraphViewChanged(L"GraphViewChanged");
|
||||||
|
StringReference FunctionRemoved(L"FunctionRemoved");
|
||||||
|
StringReference GraphViewBestFitChanged(L"GraphViewBestFitChanged");
|
||||||
|
StringReference AlwaysOnTop(L"AlwaysOnTop");
|
||||||
|
StringReference BitShiftRadioButtonContent(L"BitShiftRadioButtonContent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +106,15 @@ NarratorAnnouncement ^ CalculatorAnnouncement::GetHistoryClearedAnnouncement(Str
|
||||||
announcement, CalculatorActivityIds::HistoryCleared, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::MostRecent);
|
announcement, CalculatorActivityIds::HistoryCleared, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::MostRecent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetHistorySlotClearedAnnouncement(String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement,
|
||||||
|
CalculatorActivityIds::HistorySlotCleared,
|
||||||
|
AutomationNotificationKind::ItemRemoved,
|
||||||
|
AutomationNotificationProcessing::ImportantMostRecent);
|
||||||
|
}
|
||||||
|
|
||||||
NarratorAnnouncement ^ CalculatorAnnouncement::GetCategoryNameChangedAnnouncement(String ^ announcement)
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetCategoryNameChangedAnnouncement(String ^ announcement)
|
||||||
{
|
{
|
||||||
return ref new NarratorAnnouncement(
|
return ref new NarratorAnnouncement(
|
||||||
|
@ -140,3 +156,51 @@ NarratorAnnouncement ^ CalculatorAnnouncement::GetNoRightParenthesisAddedAnnounc
|
||||||
AutomationNotificationKind::ActionCompleted,
|
AutomationNotificationKind::ActionCompleted,
|
||||||
AutomationNotificationProcessing::ImportantMostRecent);
|
AutomationNotificationProcessing::ImportantMostRecent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetGraphModeChangedAnnouncement(String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement,
|
||||||
|
CalculatorActivityIds::GraphModeChanged,
|
||||||
|
AutomationNotificationKind::ActionCompleted,
|
||||||
|
AutomationNotificationProcessing::ImportantMostRecent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetGraphViewChangedAnnouncement(String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement,
|
||||||
|
CalculatorActivityIds::GraphViewChanged,
|
||||||
|
AutomationNotificationKind::ActionCompleted,
|
||||||
|
AutomationNotificationProcessing::CurrentThenMostRecent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetFunctionRemovedAnnouncement(String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement, CalculatorActivityIds::FunctionRemoved, AutomationNotificationKind::ItemRemoved, AutomationNotificationProcessing::MostRecent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetGraphViewBestFitChangedAnnouncement(Platform::String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement,
|
||||||
|
CalculatorActivityIds::GraphViewBestFitChanged,
|
||||||
|
AutomationNotificationKind::ActionCompleted,
|
||||||
|
AutomationNotificationProcessing::MostRecent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetAlwaysOnTopChangedAnnouncement(String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement, CalculatorActivityIds::AlwaysOnTop, AutomationNotificationKind::ActionCompleted, AutomationNotificationProcessing::ImportantMostRecent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NarratorAnnouncement ^ CalculatorAnnouncement::GetBitShiftRadioButtonCheckedAnnouncement(String ^ announcement)
|
||||||
|
{
|
||||||
|
return ref new NarratorAnnouncement(
|
||||||
|
announcement,
|
||||||
|
CalculatorActivityIds::BitShiftRadioButtonContent,
|
||||||
|
AutomationNotificationKind::ActionCompleted,
|
||||||
|
AutomationNotificationProcessing::ImportantMostRecent);
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ public
|
||||||
static NarratorAnnouncement ^ GetMemoryItemAddedAnnouncement(Platform::String ^ announcement);
|
static NarratorAnnouncement ^ GetMemoryItemAddedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
static NarratorAnnouncement ^ GetHistoryClearedAnnouncement(Platform::String ^ announcement);
|
static NarratorAnnouncement ^ GetHistoryClearedAnnouncement(Platform::String ^ announcement);
|
||||||
|
static NarratorAnnouncement ^ GetHistorySlotClearedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
static NarratorAnnouncement ^ GetCategoryNameChangedAnnouncement(Platform::String ^ announcement);
|
static NarratorAnnouncement ^ GetCategoryNameChangedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
|
@ -66,5 +67,16 @@ public
|
||||||
|
|
||||||
static NarratorAnnouncement ^ GetOpenParenthesisCountChangedAnnouncement(Platform::String ^ announcement);
|
static NarratorAnnouncement ^ GetOpenParenthesisCountChangedAnnouncement(Platform::String ^ announcement);
|
||||||
static NarratorAnnouncement ^ GetNoRightParenthesisAddedAnnouncement(Platform::String ^ announcement);
|
static NarratorAnnouncement ^ GetNoRightParenthesisAddedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
|
static NarratorAnnouncement ^ GetGraphModeChangedAnnouncement(Platform::String ^ announcement);
|
||||||
|
static NarratorAnnouncement ^ GetGraphViewChangedAnnouncement(Platform::String ^ announcement);
|
||||||
|
static NarratorAnnouncement ^ GetGraphViewBestFitChangedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
|
static NarratorAnnouncement ^ GetFunctionRemovedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
|
static NarratorAnnouncement ^ GetAlwaysOnTopChangedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
|
static NarratorAnnouncement ^ GetBitShiftRadioButtonCheckedAnnouncement(Platform::String ^ announcement);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "NarratorAnnouncementHostFactory.h"
|
||||||
|
#include "NotificationHost.h"
|
||||||
|
#include "LiveRegionHost.h"
|
||||||
|
|
||||||
|
using namespace CalculatorApp::Common::Automation;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::s_hostProducer;
|
||||||
|
vector<INarratorAnnouncementHost ^> NarratorAnnouncementHostFactory::s_hosts;
|
||||||
|
|
||||||
|
// This static variable is used only to call the initialization function, to initialize the other static variables.
|
||||||
|
int NarratorAnnouncementHostFactory::s_init = NarratorAnnouncementHostFactory::Initialize();
|
||||||
|
int NarratorAnnouncementHostFactory::Initialize()
|
||||||
|
{
|
||||||
|
RegisterHosts();
|
||||||
|
NarratorAnnouncementHostFactory::s_hostProducer = GetHostProducer();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, there are two type of announcement hosts.
|
||||||
|
// We'd prefer to use Notification if it's available and fall back to LiveRegion
|
||||||
|
// if not. The availability of the host depends on the version of the OS the app is running on.
|
||||||
|
// When the app switches to min version RS3, the LiveRegionHost can be removed and we will always
|
||||||
|
// use NotificationHost.
|
||||||
|
// TODO - MSFT 12735088
|
||||||
|
void NarratorAnnouncementHostFactory::RegisterHosts()
|
||||||
|
{
|
||||||
|
// The host that will be used is the first available host,
|
||||||
|
// therefore, order of hosts is important here.
|
||||||
|
NarratorAnnouncementHostFactory::s_hosts = { ref new NotificationHost(), ref new LiveRegionHost() };
|
||||||
|
}
|
||||||
|
|
||||||
|
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::GetHostProducer()
|
||||||
|
{
|
||||||
|
for (INarratorAnnouncementHost ^ host : NarratorAnnouncementHostFactory::s_hosts)
|
||||||
|
{
|
||||||
|
if (host->IsHostAvailable())
|
||||||
|
{
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false && L"No suitable AnnouncementHost was found.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::MakeHost()
|
||||||
|
{
|
||||||
|
if (NarratorAnnouncementHostFactory::s_hostProducer == nullptr)
|
||||||
|
{
|
||||||
|
assert(false && L"No host producer has been assigned.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NarratorAnnouncementHostFactory::s_hostProducer->MakeHost();
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "INarratorAnnouncementHost.h"
|
||||||
|
|
||||||
|
// Declaration of the NarratorAnnouncementHostFactory class.
|
||||||
|
// This class exists to hide the construction of a concrete INarratorAnnouncementHost.
|
||||||
|
// Depending on the version of the OS the app is running on, the factory will return
|
||||||
|
// an announcement host appropriate for that version.
|
||||||
|
|
||||||
|
namespace CalculatorApp::Common::Automation
|
||||||
|
{
|
||||||
|
class NarratorAnnouncementHostFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static INarratorAnnouncementHost ^ MakeHost();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NarratorAnnouncementHostFactory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Initialize();
|
||||||
|
static void RegisterHosts();
|
||||||
|
static INarratorAnnouncementHost ^ GetHostProducer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int s_init;
|
||||||
|
static INarratorAnnouncementHost ^ s_hostProducer;
|
||||||
|
static std::vector<INarratorAnnouncementHost ^> s_hosts;
|
||||||
|
};
|
||||||
|
}
|
97
src/CalcViewModel/Common/Automation/NotificationHost.cpp
Normal file
97
src/CalcViewModel/Common/Automation/NotificationHost.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
// 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;
|
||||||
|
}
|
34
src/CalcViewModel/Common/Automation/NotificationHost.h
Normal file
34
src/CalcViewModel/Common/Automation/NotificationHost.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "INarratorAnnouncementHost.h"
|
||||||
|
|
||||||
|
// Declaration of the NotificationHost class.
|
||||||
|
// This class announces NarratorAnnouncements using the RaiseNotification API
|
||||||
|
// available in RS3.
|
||||||
|
|
||||||
|
namespace CalculatorApp::Common::Automation
|
||||||
|
{
|
||||||
|
public
|
||||||
|
ref class NotificationHost sealed : public INarratorAnnouncementHost
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NotificationHost();
|
||||||
|
|
||||||
|
virtual bool IsHostAvailable();
|
||||||
|
virtual INarratorAnnouncementHost ^ MakeHost();
|
||||||
|
|
||||||
|
virtual void Announce(NarratorAnnouncement ^ announcement);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind
|
||||||
|
GetWindowsNotificationKind(CalculatorApp::Common::Automation::AutomationNotificationKind customKindType);
|
||||||
|
|
||||||
|
static Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing
|
||||||
|
GetWindowsNotificationProcessing(CalculatorApp::Common::Automation::AutomationNotificationProcessing customProcessingType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Windows::UI::Xaml::UIElement ^ m_host;
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#include "pch.h"
|
|
||||||
#include "BindableBase.h"
|
|
||||||
|
|
||||||
using namespace CalculatorApp::Common;
|
|
||||||
|
|
||||||
using namespace Platform;
|
|
||||||
using namespace Windows::UI::Xaml::Data;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Notifies listeners that a property value has changed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">Name of the property used to notify listeners.</param>
|
|
||||||
void BindableBase::OnPropertyChanged(String ^ propertyName)
|
|
||||||
{
|
|
||||||
PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
Windows::UI::Xaml::Data::ICustomProperty ^ BindableBase::GetCustomProperty(Platform::String ^ name)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Windows::UI::Xaml::Data::ICustomProperty ^ BindableBase::GetIndexedProperty(Platform::String ^ name, Windows::UI::Xaml::Interop::TypeName type)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform::String ^ BindableBase::GetStringRepresentation()
|
|
||||||
{
|
|
||||||
return this->ToString();
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
|
||||||
namespace Common
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of <see cref="INotifyPropertyChanged"/> to simplify models.
|
|
||||||
/// </summary>
|
|
||||||
[Windows::Foundation::Metadata::WebHostHidden] public ref class BindableBase : Windows::UI::Xaml::DependencyObject,
|
|
||||||
Windows::UI::Xaml::Data::INotifyPropertyChanged,
|
|
||||||
Windows::UI::Xaml::Data::ICustomPropertyProvider
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// ICustomPropertyProvider
|
|
||||||
virtual Windows::UI::Xaml::Data::ICustomProperty ^ GetCustomProperty(Platform::String ^ name);
|
|
||||||
virtual Windows::UI::Xaml::Data::ICustomProperty ^ GetIndexedProperty(Platform::String ^ name, Windows::UI::Xaml::Interop::TypeName type);
|
|
||||||
virtual Platform::String ^ GetStringRepresentation();
|
|
||||||
|
|
||||||
property Windows::UI::Xaml::Interop::TypeName Type
|
|
||||||
{
|
|
||||||
virtual Windows::UI::Xaml::Interop::TypeName get()
|
|
||||||
{
|
|
||||||
return this->GetType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void OnPropertyChanged(Platform::String ^ propertyName);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -109,7 +109,7 @@ public
|
||||||
InvCoth = (int) CM::Command::CommandACOTH,
|
InvCoth = (int) CM::Command::CommandACOTH,
|
||||||
CubeRoot = (int) CM::Command::CommandCUBEROOT,
|
CubeRoot = (int) CM::Command::CommandCUBEROOT,
|
||||||
TwoPowerX = (int) CM::Command::CommandPOW2,
|
TwoPowerX = (int) CM::Command::CommandPOW2,
|
||||||
LogBaseX = (int) CM::Command::CommandLogBaseX,
|
LogBaseY = (int) CM::Command::CommandLogBaseY,
|
||||||
Nand = (int) CM::Command::CommandNand,
|
Nand = (int) CM::Command::CommandNand,
|
||||||
Nor = (int) CM::Command::CommandNor,
|
Nor = (int) CM::Command::CommandNor,
|
||||||
Abs = (int) CM::Command::CommandAbs,
|
Abs = (int) CM::Command::CommandAbs,
|
||||||
|
@ -194,6 +194,15 @@ public
|
||||||
MemoryRecall = (int)CM::Command::CommandRECALL,
|
MemoryRecall = (int)CM::Command::CommandRECALL,
|
||||||
MemoryClear = (int)CM::Command::CommandMCLEAR,
|
MemoryClear = (int)CM::Command::CommandMCLEAR,
|
||||||
BitflipButton = 1000,
|
BitflipButton = 1000,
|
||||||
FullKeypadButton = 1001
|
FullKeypadButton = 1001,
|
||||||
|
|
||||||
|
// Buttons used in graphing calculator
|
||||||
|
LessThan,
|
||||||
|
LessThanOrEqualTo,
|
||||||
|
GreaterThan,
|
||||||
|
GreaterThanOrEqualTo,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Submit
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#include "pch.h"
|
|
||||||
#include "ConversionResultTaskHelper.h"
|
|
||||||
|
|
||||||
using namespace CalculatorApp::Common;
|
|
||||||
using namespace concurrency;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
ConversionResultTaskHelper::ConversionResultTaskHelper(unsigned int delay, const function<void()> functionToRun)
|
|
||||||
: m_delay{ delay }
|
|
||||||
, m_storedFunction{ functionToRun }
|
|
||||||
{
|
|
||||||
auto token = m_cts.get_token();
|
|
||||||
auto delayTask = CompleteAfter(delay);
|
|
||||||
delayTask.then(
|
|
||||||
[this, token]() {
|
|
||||||
if (!token.is_canceled())
|
|
||||||
{
|
|
||||||
m_storedFunction();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
task_continuation_context::use_current());
|
|
||||||
}
|
|
||||||
|
|
||||||
ConversionResultTaskHelper::~ConversionResultTaskHelper()
|
|
||||||
{
|
|
||||||
m_cts.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma optimize("", off)
|
|
||||||
// Creates a task that completes after the specified delay.
|
|
||||||
//
|
|
||||||
// Taken from: How to: Create a Task that Completes After a Delay
|
|
||||||
// https://msdn.microsoft.com/en-us/library/hh873170.aspx
|
|
||||||
task<void> ConversionResultTaskHelper::CompleteAfter(unsigned int timeout)
|
|
||||||
{
|
|
||||||
co_await winrt::resume_after(winrt::Windows::Foundation::TimeSpan{ std::chrono::duration<uint32_t, std::milli>(timeout) });
|
|
||||||
};
|
|
||||||
#pragma optimize("", on)
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
|
||||||
namespace Common
|
|
||||||
{
|
|
||||||
class ConversionResultTaskHelper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ConversionResultTaskHelper(unsigned int delay, const std::function<void()> functionToRun);
|
|
||||||
~ConversionResultTaskHelper();
|
|
||||||
|
|
||||||
private:
|
|
||||||
concurrency::task<void> CompleteAfter(unsigned int timeout);
|
|
||||||
|
|
||||||
unsigned int m_delay;
|
|
||||||
concurrency::cancellation_token_source m_cts;
|
|
||||||
const std::function<void()> m_storedFunction;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -310,6 +310,9 @@ bool CopyPasteManager::ExpressionRegExMatch(
|
||||||
|
|
||||||
if (operandMatched)
|
if (operandMatched)
|
||||||
{
|
{
|
||||||
|
// Remember the sign of the operand
|
||||||
|
bool isNegativeValue = operand->Data()[0] == L'-';
|
||||||
|
|
||||||
// Remove characters that are valid in the expression but we do not want to include in length calculations
|
// 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.
|
// or which will break conversion from string-to-ULL.
|
||||||
auto operandValue = SanitizeOperand(operand);
|
auto operandValue = SanitizeOperand(operand);
|
||||||
|
@ -332,7 +335,11 @@ bool CopyPasteManager::ExpressionRegExMatch(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operandAsULL->Value > maxOperandLengthAndValue.maxValue)
|
// Calculate how much we exceed the maxValue.
|
||||||
|
// In case we exceed it for 1 only, and working with negative number - that's a corner case for max signed values (e.g. -32768)
|
||||||
|
bool isOverflow = operandAsULL->Value > maxOperandLengthAndValue.maxValue;
|
||||||
|
bool isMaxNegativeValue = operandAsULL->Value - 1 == maxOperandLengthAndValue.maxValue;
|
||||||
|
if (isOverflow && !(isNegativeValue && isMaxNegativeValue))
|
||||||
{
|
{
|
||||||
expMatched = false;
|
expMatched = false;
|
||||||
break;
|
break;
|
||||||
|
@ -594,9 +601,11 @@ ULONG32 CopyPasteManager::ProgrammerOperandLength(Platform::String ^ operand, Nu
|
||||||
// Indian rupee(₹) - 8377
|
// Indian rupee(₹) - 8377
|
||||||
// pound(£) - 163
|
// pound(£) - 163
|
||||||
// euro(€) - 8364
|
// euro(€) - 8364
|
||||||
|
// non-breaking whitespace - 160
|
||||||
Platform::String ^ CopyPasteManager::RemoveUnwantedCharsFromString(Platform::String ^ input)
|
Platform::String ^ CopyPasteManager::RemoveUnwantedCharsFromString(Platform::String ^ input)
|
||||||
{
|
{
|
||||||
constexpr wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237 };
|
constexpr wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237, 160 };
|
||||||
|
input = CalculatorApp::Common::LocalizationSettings::GetInstance().RemoveGroupSeparators(input);
|
||||||
return ref new String(Utils::RemoveUnwantedCharsFromString(input->Data(), unWantedChars).c_str());
|
return ref new String(Utils::RemoveUnwantedCharsFromString(input->Data(), unWantedChars).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,850 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#include "pch.h"
|
|
||||||
#include "KeyboardShortcutManager.h"
|
|
||||||
#include "AppResourceProvider.h"
|
|
||||||
#include "ApplicationViewModel.h"
|
|
||||||
#include "LocalizationSettings.h"
|
|
||||||
|
|
||||||
using namespace Concurrency;
|
|
||||||
using namespace Platform;
|
|
||||||
using namespace std;
|
|
||||||
using namespace Windows::ApplicationModel::Resources;
|
|
||||||
using namespace Windows::UI::Xaml;
|
|
||||||
using namespace Windows::UI::Xaml::Controls;
|
|
||||||
using namespace Windows::Foundation;
|
|
||||||
using namespace Windows::Foundation::Collections;
|
|
||||||
using namespace Windows::UI::Core;
|
|
||||||
using namespace Windows::UI::Xaml::Controls::Primitives;
|
|
||||||
using namespace Windows::System;
|
|
||||||
using namespace Utils;
|
|
||||||
using namespace CalculatorApp;
|
|
||||||
using namespace CalculatorApp::Common;
|
|
||||||
using namespace CalculatorApp::ViewModel;
|
|
||||||
|
|
||||||
namespace MUXC = Microsoft::UI::Xaml::Controls;
|
|
||||||
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, Character);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKey);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlChord);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyShiftChord);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyAltChord);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlShiftChord);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyInverseChord);
|
|
||||||
DEPENDENCY_PROPERTY_INITIALIZATION(KeyboardShortcutManager, VirtualKeyControlInverseChord);
|
|
||||||
|
|
||||||
static multimap<int, multimap<wchar_t, WeakReference>> s_CharacterForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeysForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyControlChordsForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyShiftChordsForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyAltChordsForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyControlShiftChordsForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyInverseChordsForButtons;
|
|
||||||
static multimap<int, multimap<MyVirtualKey, WeakReference>> s_VirtualKeyControlInverseChordsForButtons;
|
|
||||||
|
|
||||||
static multimap<int, bool> s_ShiftKeyPressed;
|
|
||||||
static multimap<int, bool> s_ControlKeyPressed;
|
|
||||||
static multimap<int, bool> s_ShiftButtonChecked;
|
|
||||||
static multimap<int, bool> s_IsDropDownOpen;
|
|
||||||
|
|
||||||
static reader_writer_lock s_keyboardShortcutMapLock;
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
|
||||||
namespace Common
|
|
||||||
{
|
|
||||||
// Lights up all of the buttons in the given range
|
|
||||||
// The range is defined by a pair of iterators
|
|
||||||
template <typename T>
|
|
||||||
void LightUpButtons(const T& buttons)
|
|
||||||
{
|
|
||||||
auto iterator = buttons.first;
|
|
||||||
for (; iterator != buttons.second; ++iterator)
|
|
||||||
{
|
|
||||||
auto button = iterator->second.Resolve<ButtonBase>();
|
|
||||||
if (button && button->IsEnabled)
|
|
||||||
{
|
|
||||||
LightUpButton(button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LightUpButton(ButtonBase ^ button)
|
|
||||||
{
|
|
||||||
// If the button is a toggle button then we don't need
|
|
||||||
// to change the UI of the button
|
|
||||||
if (dynamic_cast<ToggleButton ^>(button))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The button will go into the visual Pressed state with this call
|
|
||||||
VisualStateManager::GoToState(button, "Pressed", true);
|
|
||||||
|
|
||||||
// This timer will fire after lightUpTime and make the button
|
|
||||||
// go back to the normal state.
|
|
||||||
// This timer will only fire once after which it will be destroyed
|
|
||||||
auto timer = ref new DispatcherTimer();
|
|
||||||
TimeSpan lightUpTime{};
|
|
||||||
lightUpTime.Duration = 500000L; // Half second (in 100-ns units)
|
|
||||||
timer->Interval = lightUpTime;
|
|
||||||
|
|
||||||
WeakReference timerWeakReference(timer);
|
|
||||||
WeakReference buttonWeakReference(button);
|
|
||||||
timer->Tick += ref new EventHandler<Object ^>([buttonWeakReference, timerWeakReference](Object ^, Object ^) {
|
|
||||||
auto button = buttonWeakReference.Resolve<ButtonBase>();
|
|
||||||
if (button)
|
|
||||||
{
|
|
||||||
VisualStateManager::GoToState(button, "Normal", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel the timer after we're done so it only fires once
|
|
||||||
auto timer = timerWeakReference.Resolve<DispatcherTimer>();
|
|
||||||
if (timer)
|
|
||||||
{
|
|
||||||
timer->Stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
timer->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Looks for the first button reference that it can resolve
|
|
||||||
// and execute its command.
|
|
||||||
// NOTE: It is assumed that all buttons associated with a particular
|
|
||||||
// key have the same command
|
|
||||||
template <typename T>
|
|
||||||
void RunFirstEnabledButtonCommand(const T& buttons)
|
|
||||||
{
|
|
||||||
auto buttonIterator = buttons.first;
|
|
||||||
for (; buttonIterator != buttons.second; ++buttonIterator)
|
|
||||||
{
|
|
||||||
auto button = buttonIterator->second.Resolve<ButtonBase>();
|
|
||||||
if (button && button->IsEnabled)
|
|
||||||
{
|
|
||||||
RunButtonCommand(button);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunButtonCommand(ButtonBase ^ button)
|
|
||||||
{
|
|
||||||
if (button->IsEnabled)
|
|
||||||
{
|
|
||||||
auto command = button->Command;
|
|
||||||
auto parameter = button->CommandParameter;
|
|
||||||
if (command && command->CanExecute(parameter))
|
|
||||||
{
|
|
||||||
command->Execute(parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto radio = dynamic_cast<RadioButton ^>(button);
|
|
||||||
if (radio)
|
|
||||||
{
|
|
||||||
radio->IsChecked = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto toggle = dynamic_cast<ToggleButton ^>(button);
|
|
||||||
if (toggle)
|
|
||||||
{
|
|
||||||
toggle->IsChecked = !toggle->IsChecked->Value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static multimap<int, bool> s_ignoreNextEscape;
|
|
||||||
static multimap<int, bool> s_keepIgnoringEscape;
|
|
||||||
static multimap<int, bool> s_fHonorShortcuts;
|
|
||||||
static multimap<int, bool> s_fHandledEnter;
|
|
||||||
static multimap<int, Flyout ^> s_AboutFlyout;
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::IgnoreEscape(bool onlyOnce)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_ignoreNextEscape.find(viewId) != s_ignoreNextEscape.end())
|
|
||||||
{
|
|
||||||
s_ignoreNextEscape.erase(viewId);
|
|
||||||
s_ignoreNextEscape.insert(std::make_pair(viewId, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_keepIgnoringEscape.find(viewId) != s_keepIgnoringEscape.end())
|
|
||||||
{
|
|
||||||
s_keepIgnoringEscape.erase(viewId);
|
|
||||||
s_keepIgnoringEscape.insert(std::make_pair(viewId, !onlyOnce));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::HonorEscape()
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_ignoreNextEscape.find(viewId) != s_ignoreNextEscape.end())
|
|
||||||
{
|
|
||||||
s_ignoreNextEscape.erase(viewId);
|
|
||||||
s_ignoreNextEscape.insert(std::make_pair(viewId, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_keepIgnoringEscape.find(viewId) != s_keepIgnoringEscape.end())
|
|
||||||
{
|
|
||||||
s_keepIgnoringEscape.erase(viewId);
|
|
||||||
s_keepIgnoringEscape.insert(std::make_pair(viewId, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnCharacterPropertyChanged(DependencyObject ^ target, String ^ oldValue, String ^ newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto button = safe_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_CharacterForButtons.find(viewId);
|
|
||||||
|
|
||||||
if (iterViewMap != s_CharacterForButtons.end())
|
|
||||||
{
|
|
||||||
if (oldValue)
|
|
||||||
{
|
|
||||||
iterViewMap->second.erase(oldValue->Data()[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newValue)
|
|
||||||
{
|
|
||||||
if (newValue == L".")
|
|
||||||
{
|
|
||||||
wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator();
|
|
||||||
iterViewMap->second.insert(std::make_pair(decSep, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue->Data()[0], WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_CharacterForButtons.insert(std::make_pair(viewId, std::multimap<wchar_t, WeakReference>()));
|
|
||||||
|
|
||||||
if (newValue == L".")
|
|
||||||
{
|
|
||||||
wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator();
|
|
||||||
s_CharacterForButtons.find(viewId)->second.insert(std::make_pair(decSep, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_CharacterForButtons.find(viewId)->second.insert(std::make_pair(newValue->Data()[0], WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto button = static_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeysForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeysForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeysForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeysForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyControlChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
Control ^ control = dynamic_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
if (control == nullptr)
|
|
||||||
{
|
|
||||||
// Handling Ctrl+E shortcut for Date Calc, target would be NavigationView^ in that case
|
|
||||||
control = safe_cast<MUXC::NavigationView ^>(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeyControlChordsForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeyControlChordsForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(control)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeyControlChordsForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeyControlChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(control)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyShiftChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto button = safe_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeyShiftChordsForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeyShiftChordsForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeyShiftChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyAltChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
MUXC::NavigationView ^ navView = safe_cast<MUXC::NavigationView ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeyAltChordsForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeyAltChordsForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(navView)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeyAltChordsForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeyAltChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(navView)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyControlShiftChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto button = safe_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeyControlShiftChordsForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeyControlShiftChordsForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyInverseChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto button = safe_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeyInverseChordsForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeyInverseChordsForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeyInverseChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnVirtualKeyControlInverseChordPropertyChanged(DependencyObject ^ target, MyVirtualKey /*oldValue*/, MyVirtualKey newValue)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto button = safe_cast<ButtonBase ^>(target);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId);
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end())
|
|
||||||
{
|
|
||||||
iterViewMap->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the View Id is not already registered, then register it and make the entry
|
|
||||||
s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(viewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
s_VirtualKeyControlInverseChordsForButtons.find(viewId)->second.insert(std::make_pair(newValue, WeakReference(button)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the three event handlers below we will not mark the event as handled
|
|
||||||
// because this is a supplemental operation and we don't want to interfere with
|
|
||||||
// the normal keyboard handling.
|
|
||||||
void KeyboardShortcutManager::OnCharacterReceivedHandler(CoreWindow ^ sender, CharacterReceivedEventArgs ^ args)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId);
|
|
||||||
|
|
||||||
if (currentHonorShortcuts != s_fHonorShortcuts.end())
|
|
||||||
{
|
|
||||||
if (currentHonorShortcuts->second)
|
|
||||||
{
|
|
||||||
wchar_t character = static_cast<wchar_t>(args->KeyCode);
|
|
||||||
auto buttons = s_CharacterForButtons.find(viewId)->second.equal_range(character);
|
|
||||||
|
|
||||||
RunFirstEnabledButtonCommand(buttons);
|
|
||||||
|
|
||||||
LightUpButtons(buttons);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::multimap<MyVirtualKey, WeakReference>& GetCurrentKeyDictionary(MyVirtualKey key, bool altPressed = false)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (altPressed)
|
|
||||||
{
|
|
||||||
return s_VirtualKeyAltChordsForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
else if (
|
|
||||||
(s_ShiftKeyPressed.find(viewId)->second)
|
|
||||||
&& ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down))
|
|
||||||
{
|
|
||||||
return s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
else if (s_ShiftKeyPressed.find(viewId)->second)
|
|
||||||
{
|
|
||||||
return s_VirtualKeyShiftChordsForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
else if (s_ShiftButtonChecked.find(viewId)->second)
|
|
||||||
{
|
|
||||||
if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down)
|
|
||||||
{
|
|
||||||
auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId);
|
|
||||||
if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end())
|
|
||||||
{
|
|
||||||
for (auto iterator = iterViewMap->second.begin(); iterator != iterViewMap->second.end(); ++iterator)
|
|
||||||
{
|
|
||||||
if (key == iterator->first)
|
|
||||||
{
|
|
||||||
return s_VirtualKeyControlInverseChordsForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto iterViewMap = s_VirtualKeyControlInverseChordsForButtons.find(viewId);
|
|
||||||
if (iterViewMap != s_VirtualKeyControlInverseChordsForButtons.end())
|
|
||||||
{
|
|
||||||
for (auto iterator = iterViewMap->second.begin(); iterator != iterViewMap->second.end(); ++iterator)
|
|
||||||
{
|
|
||||||
if (key == iterator->first)
|
|
||||||
{
|
|
||||||
return s_VirtualKeyInverseChordsForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down)
|
|
||||||
{
|
|
||||||
return s_VirtualKeyControlChordsForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return s_VirtualKeysForButtons.find(viewId)->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow ^ sender, KeyEventArgs ^ args)
|
|
||||||
{
|
|
||||||
// If keyboard shortcuts like Ctrl+C or Ctrl+V are not handled
|
|
||||||
if (!args->Handled)
|
|
||||||
{
|
|
||||||
auto key = args->VirtualKey;
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
auto currentControlKeyPressed = s_ControlKeyPressed.find(viewId);
|
|
||||||
auto currentShiftKeyPressed = s_ShiftKeyPressed.find(viewId);
|
|
||||||
|
|
||||||
bool isControlKeyPressed = (currentControlKeyPressed != s_ControlKeyPressed.end()) && (currentControlKeyPressed->second);
|
|
||||||
bool isShiftKeyPressed = (currentShiftKeyPressed != s_ShiftKeyPressed.end()) && (currentShiftKeyPressed->second);
|
|
||||||
|
|
||||||
// Handle Ctrl + E for DateCalculator
|
|
||||||
if ((key == VirtualKey::E) && isControlKeyPressed && !isShiftKeyPressed)
|
|
||||||
{
|
|
||||||
const auto& lookupMap = GetCurrentKeyDictionary(static_cast<MyVirtualKey>(key));
|
|
||||||
auto buttons = lookupMap.equal_range(static_cast<MyVirtualKey>(key));
|
|
||||||
auto navView = buttons.first->second.Resolve<MUXC::NavigationView>();
|
|
||||||
auto appViewModel = safe_cast<ApplicationViewModel ^>(navView->DataContext);
|
|
||||||
appViewModel->Mode = ViewMode::Date;
|
|
||||||
auto categoryName = AppResourceProvider::GetInstance()->GetResourceString(L"DateCalculationModeText");
|
|
||||||
appViewModel->CategoryName = categoryName;
|
|
||||||
|
|
||||||
auto menuItems = static_cast<IObservableVector<Object ^> ^>(navView->MenuItemsSource);
|
|
||||||
auto flatIndex = NavCategory::GetFlatIndex(ViewMode::Date);
|
|
||||||
navView->SelectedItem = menuItems->GetAt(flatIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId);
|
|
||||||
|
|
||||||
auto currentIgnoreNextEscape = s_ignoreNextEscape.find(viewId);
|
|
||||||
|
|
||||||
if (currentIgnoreNextEscape != s_ignoreNextEscape.end())
|
|
||||||
{
|
|
||||||
if (currentIgnoreNextEscape->second && key == VirtualKey::Escape)
|
|
||||||
{
|
|
||||||
auto currentKeepIgnoringEscape = s_keepIgnoringEscape.find(viewId);
|
|
||||||
|
|
||||||
if (currentKeepIgnoringEscape != s_keepIgnoringEscape.end())
|
|
||||||
{
|
|
||||||
if (!currentKeepIgnoringEscape->second)
|
|
||||||
{
|
|
||||||
HonorEscape();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == VirtualKey::Control)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto currControlKeyPressed = s_ControlKeyPressed.find(viewId);
|
|
||||||
|
|
||||||
if (currControlKeyPressed != s_ControlKeyPressed.end())
|
|
||||||
{
|
|
||||||
s_ControlKeyPressed.erase(viewId);
|
|
||||||
s_ControlKeyPressed.insert(std::make_pair(viewId, true));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (key == VirtualKey::Shift)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto currShiftKeyPressed = s_ShiftKeyPressed.find(viewId);
|
|
||||||
|
|
||||||
if (currShiftKeyPressed != s_ShiftKeyPressed.end())
|
|
||||||
{
|
|
||||||
s_ShiftKeyPressed.erase(viewId);
|
|
||||||
s_ShiftKeyPressed.insert(std::make_pair(viewId, true));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& lookupMap = GetCurrentKeyDictionary(static_cast<MyVirtualKey>(key));
|
|
||||||
auto buttons = lookupMap.equal_range(static_cast<MyVirtualKey>(key));
|
|
||||||
|
|
||||||
auto currentIsDropDownOpen = s_IsDropDownOpen.find(viewId);
|
|
||||||
|
|
||||||
if (currentHonorShortcuts != s_fHonorShortcuts.end())
|
|
||||||
{
|
|
||||||
if (currentHonorShortcuts->second)
|
|
||||||
{
|
|
||||||
RunFirstEnabledButtonCommand(buttons);
|
|
||||||
|
|
||||||
// Ctrl+C and Ctrl+V shifts focus to some button because of which enter doesn't work after copy/paste. So don't shift focus if Ctrl+C or Ctrl+V
|
|
||||||
// is pressed. When drop down is open, pressing escape shifts focus to clear button. So dont's shift focus if drop down is open. Ctrl+Insert is
|
|
||||||
// equivalent to Ctrl+C and Shift+Insert is equivalent to Ctrl+V
|
|
||||||
if (currentIsDropDownOpen != s_IsDropDownOpen.end() && !currentIsDropDownOpen->second)
|
|
||||||
{
|
|
||||||
// Do not Light Up Buttons when Ctrl+C, Ctrl+V, Ctrl+Insert or Shift+Insert is pressed
|
|
||||||
if (!(isControlKeyPressed && (key == VirtualKey::C || key == VirtualKey::V || key == VirtualKey::Insert))
|
|
||||||
&& !(isShiftKeyPressed && (key == VirtualKey::Insert)))
|
|
||||||
{
|
|
||||||
LightUpButtons(buttons);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnKeyUpHandler(CoreWindow ^ sender, KeyEventArgs ^ args)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto key = args->VirtualKey;
|
|
||||||
|
|
||||||
if (key == VirtualKey::Shift)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto currentShiftKeyPressed = s_ShiftKeyPressed.find(viewId);
|
|
||||||
|
|
||||||
if (currentShiftKeyPressed != s_ShiftKeyPressed.end())
|
|
||||||
{
|
|
||||||
s_ShiftKeyPressed.erase(viewId);
|
|
||||||
s_ShiftKeyPressed.insert(std::make_pair(viewId, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (key == VirtualKey::Control)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
auto currControlKeyPressed = s_ControlKeyPressed.find(viewId);
|
|
||||||
|
|
||||||
if (currControlKeyPressed != s_ControlKeyPressed.end())
|
|
||||||
{
|
|
||||||
s_ControlKeyPressed.erase(viewId);
|
|
||||||
s_ControlKeyPressed.insert(std::make_pair(viewId, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnAcceleratorKeyActivated(CoreDispatcher ^, AcceleratorKeyEventArgs ^ args)
|
|
||||||
{
|
|
||||||
if (args->KeyStatus.IsKeyReleased)
|
|
||||||
{
|
|
||||||
auto key = args->VirtualKey;
|
|
||||||
bool altPressed = args->KeyStatus.IsMenuKeyDown;
|
|
||||||
|
|
||||||
// If the Alt/Menu key is not pressed then we don't care about the key anymore
|
|
||||||
if (!altPressed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& lookupMap = GetCurrentKeyDictionary(static_cast<MyVirtualKey>(key), altPressed);
|
|
||||||
auto listItems = lookupMap.equal_range(static_cast<MyVirtualKey>(key));
|
|
||||||
for (auto listIterator = listItems.first; listIterator != listItems.second; ++listIterator)
|
|
||||||
{
|
|
||||||
auto item = listIterator->second.Resolve<MUXC::NavigationView>();
|
|
||||||
if (item != nullptr)
|
|
||||||
{
|
|
||||||
auto navView = safe_cast<MUXC::NavigationView ^>(item);
|
|
||||||
|
|
||||||
auto menuItems = static_cast<IObservableVector<Object ^> ^>(navView->MenuItemsSource);
|
|
||||||
if (menuItems != nullptr)
|
|
||||||
{
|
|
||||||
auto vm = safe_cast<ApplicationViewModel ^>(navView->DataContext);
|
|
||||||
if (nullptr != vm)
|
|
||||||
{
|
|
||||||
ViewMode toMode = NavCategory::GetViewModeForVirtualKey(static_cast<MyVirtualKey>(key));
|
|
||||||
auto nvi = dynamic_cast<MUXC::NavigationViewItem ^>(menuItems->GetAt(NavCategory::GetFlatIndex(toMode)));
|
|
||||||
if (nvi && nvi->IsEnabled && NavCategory::IsValidViewMode(toMode))
|
|
||||||
{
|
|
||||||
vm->Mode = toMode;
|
|
||||||
navView->SelectedItem = nvi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args->VirtualKey == VirtualKey::Escape)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
auto iterViewMap = s_AboutFlyout.find(viewId);
|
|
||||||
|
|
||||||
if ((iterViewMap != s_AboutFlyout.end()) && (iterViewMap->second != nullptr))
|
|
||||||
{
|
|
||||||
iterViewMap->second->Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::Initialize()
|
|
||||||
{
|
|
||||||
auto coreWindow = Window::Current->CoreWindow;
|
|
||||||
coreWindow->CharacterReceived +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, CharacterReceivedEventArgs ^>(&KeyboardShortcutManager::OnCharacterReceivedHandler);
|
|
||||||
coreWindow->KeyDown += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(&KeyboardShortcutManager::OnKeyDownHandler);
|
|
||||||
coreWindow->KeyUp += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(&KeyboardShortcutManager::OnKeyUpHandler);
|
|
||||||
coreWindow->Dispatcher->AcceleratorKeyActivated +=
|
|
||||||
ref new TypedEventHandler<CoreDispatcher ^, AcceleratorKeyEventArgs ^>(&KeyboardShortcutManager::OnAcceleratorKeyActivated);
|
|
||||||
|
|
||||||
KeyboardShortcutManager::RegisterNewAppViewId();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::ShiftButtonChecked(bool checked)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_ShiftButtonChecked.find(viewId) != s_ShiftButtonChecked.end())
|
|
||||||
{
|
|
||||||
s_ShiftButtonChecked.erase(viewId);
|
|
||||||
s_ShiftButtonChecked.insert(std::make_pair(viewId, checked));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::UpdateDropDownState(bool isOpen)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_IsDropDownOpen.find(viewId) != s_IsDropDownOpen.end())
|
|
||||||
{
|
|
||||||
s_IsDropDownOpen.erase(viewId);
|
|
||||||
s_IsDropDownOpen.insert(std::make_pair(viewId, isOpen));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::UpdateDropDownState(Flyout ^ aboutPageFlyout)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_AboutFlyout.find(viewId) != s_AboutFlyout.end())
|
|
||||||
{
|
|
||||||
s_AboutFlyout.erase(viewId);
|
|
||||||
s_AboutFlyout.insert(std::make_pair(viewId, aboutPageFlyout));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::HonorShortcuts(bool allow)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_fHonorShortcuts.find(viewId) != s_fHonorShortcuts.end())
|
|
||||||
{
|
|
||||||
s_fHonorShortcuts.erase(viewId);
|
|
||||||
s_fHonorShortcuts.insert(std::make_pair(viewId, allow));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::HandledEnter(bool ishandled)
|
|
||||||
{
|
|
||||||
int viewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
if (s_fHandledEnter.find(viewId) != s_fHandledEnter.end())
|
|
||||||
{
|
|
||||||
s_fHandledEnter.erase(viewId);
|
|
||||||
s_fHandledEnter.insert(std::make_pair(viewId, ishandled));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::RegisterNewAppViewId()
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
int appViewId = Utils::GetWindowId();
|
|
||||||
|
|
||||||
// Check if the View Id has already been registered
|
|
||||||
if (s_CharacterForButtons.find(appViewId) == s_CharacterForButtons.end())
|
|
||||||
{
|
|
||||||
s_CharacterForButtons.insert(std::make_pair(appViewId, std::multimap<wchar_t, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeysForButtons.find(appViewId) == s_VirtualKeysForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeysForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeyControlChordsForButtons.find(appViewId) == s_VirtualKeyControlChordsForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeyControlChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeyShiftChordsForButtons.find(appViewId) == s_VirtualKeyShiftChordsForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeyShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeyAltChordsForButtons.find(appViewId) == s_VirtualKeyAltChordsForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeyAltChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeyControlShiftChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeyInverseChordsForButtons.find(appViewId) == s_VirtualKeyInverseChordsForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeyInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_VirtualKeyControlInverseChordsForButtons.find(appViewId) == s_VirtualKeyControlInverseChordsForButtons.end())
|
|
||||||
{
|
|
||||||
s_VirtualKeyControlInverseChordsForButtons.insert(std::make_pair(appViewId, std::multimap<MyVirtualKey, WeakReference>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
s_ShiftKeyPressed.insert(std::make_pair(appViewId, false));
|
|
||||||
s_ControlKeyPressed.insert(std::make_pair(appViewId, false));
|
|
||||||
s_ShiftButtonChecked.insert(std::make_pair(appViewId, false));
|
|
||||||
s_IsDropDownOpen.insert(std::make_pair(appViewId, false));
|
|
||||||
s_ignoreNextEscape.insert(std::make_pair(appViewId, false));
|
|
||||||
s_keepIgnoringEscape.insert(std::make_pair(appViewId, false));
|
|
||||||
s_fHonorShortcuts.insert(std::make_pair(appViewId, true));
|
|
||||||
s_fHandledEnter.insert(std::make_pair(appViewId, true));
|
|
||||||
s_AboutFlyout.insert(std::make_pair(appViewId, nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardShortcutManager::OnWindowClosed(int viewId)
|
|
||||||
{
|
|
||||||
// Writer lock for the static maps
|
|
||||||
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
|
|
||||||
|
|
||||||
s_CharacterForButtons.erase(viewId);
|
|
||||||
|
|
||||||
s_VirtualKeysForButtons.erase(viewId);
|
|
||||||
s_VirtualKeyControlChordsForButtons.erase(viewId);
|
|
||||||
s_VirtualKeyShiftChordsForButtons.erase(viewId);
|
|
||||||
s_VirtualKeyAltChordsForButtons.erase(viewId);
|
|
||||||
s_VirtualKeyControlShiftChordsForButtons.erase(viewId);
|
|
||||||
s_VirtualKeyInverseChordsForButtons.erase(viewId);
|
|
||||||
s_VirtualKeyControlInverseChordsForButtons.erase(viewId);
|
|
||||||
|
|
||||||
s_ShiftKeyPressed.erase(viewId);
|
|
||||||
s_ControlKeyPressed.erase(viewId);
|
|
||||||
s_ShiftButtonChecked.erase(viewId);
|
|
||||||
s_IsDropDownOpen.erase(viewId);
|
|
||||||
s_ignoreNextEscape.erase(viewId);
|
|
||||||
s_keepIgnoringEscape.erase(viewId);
|
|
||||||
s_fHonorShortcuts.erase(viewId);
|
|
||||||
s_fHandledEnter.erase(viewId);
|
|
||||||
s_AboutFlyout.erase(viewId);
|
|
||||||
}
|
|
|
@ -545,7 +545,7 @@ unordered_map<wstring, wstring> LocalizationService::GetTokenToReadableNameMap()
|
||||||
static vector<pair<wstring, wstring>> s_noParenEngineKeyResourceMap = { // Programmer mode functions
|
static vector<pair<wstring, wstring>> s_noParenEngineKeyResourceMap = { // Programmer mode functions
|
||||||
make_pair<wstring, wstring>(L"9", L"LeftShift"),
|
make_pair<wstring, wstring>(L"9", L"LeftShift"),
|
||||||
make_pair<wstring, wstring>(L"10", L"RightShift"),
|
make_pair<wstring, wstring>(L"10", L"RightShift"),
|
||||||
make_pair<wstring, wstring>(L"LogBaseX", L"Logx"),
|
make_pair<wstring, wstring>(L"LogBaseY", L"Logy"),
|
||||||
|
|
||||||
// Y Root scientific function
|
// Y Root scientific function
|
||||||
make_pair<wstring, wstring>(L"16", L"YRoot")
|
make_pair<wstring, wstring>(L"16", L"YRoot")
|
||||||
|
|
|
@ -81,6 +81,18 @@ namespace CalculatorApp
|
||||||
{
|
{
|
||||||
return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data(), param2->Data(), param3->Data(), param4->Data());
|
return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data(), param2->Data(), param3->Data(), param4->Data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Platform::String
|
||||||
|
^ GetLocalizedString(
|
||||||
|
Platform::String ^ pMessage,
|
||||||
|
Platform::String ^ param1,
|
||||||
|
Platform::String ^ param2,
|
||||||
|
Platform::String ^ param3,
|
||||||
|
Platform::String ^ param4,
|
||||||
|
Platform::String ^ param5)
|
||||||
|
{
|
||||||
|
return LocalizationStringUtilInternal::GetLocalizedString(pMessage, param1->Data(), param2->Data(), param3->Data(), param4->Data(), param5->Data());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,17 @@
|
||||||
#include "NavCategory.h"
|
#include "NavCategory.h"
|
||||||
#include "AppResourceProvider.h"
|
#include "AppResourceProvider.h"
|
||||||
#include "Common/LocalizationStringUtil.h"
|
#include "Common/LocalizationStringUtil.h"
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
using namespace CalculatorApp;
|
using namespace CalculatorApp;
|
||||||
using namespace CalculatorApp::Common;
|
using namespace CalculatorApp::Common;
|
||||||
|
using namespace Concurrency;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace Platform::Collections;
|
using namespace Platform::Collections;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Windows::Foundation::Collections;
|
using namespace Windows::Foundation::Collections;
|
||||||
|
using namespace Windows::Management::Policies;
|
||||||
|
using namespace Windows::System;
|
||||||
|
|
||||||
namespace UCM = UnitConversionManager;
|
namespace UCM = UnitConversionManager;
|
||||||
|
|
||||||
|
@ -22,12 +26,6 @@ static constexpr bool SUPPORTS_ALL = true;
|
||||||
static constexpr bool SUPPORTS_NEGATIVE = true;
|
static constexpr bool SUPPORTS_NEGATIVE = true;
|
||||||
static constexpr bool POSITIVE_ONLY = false;
|
static constexpr bool POSITIVE_ONLY = false;
|
||||||
|
|
||||||
// The order of items in this list determines the order of groups in the menu.
|
|
||||||
static constexpr array<const NavCategoryGroupInitializer, 2> s_categoryGroupManifest = {
|
|
||||||
NavCategoryGroupInitializer{ CategoryGroupType::Calculator, L"CalculatorModeTextCaps", L"CalculatorModeText", L"CalculatorModePluralText" },
|
|
||||||
NavCategoryGroupInitializer{ CategoryGroupType::Converter, L"ConverterModeTextCaps", L"ConverterModeText", L"ConverterModePluralText" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// vvv THESE CONSTANTS SHOULD NEVER CHANGE vvv
|
// vvv THESE CONSTANTS SHOULD NEVER CHANGE vvv
|
||||||
static constexpr int STANDARD_ID = 0;
|
static constexpr int STANDARD_ID = 0;
|
||||||
static constexpr int SCIENTIFIC_ID = 1;
|
static constexpr int SCIENTIFIC_ID = 1;
|
||||||
|
@ -46,17 +44,55 @@ static constexpr int DATA_ID = 13;
|
||||||
static constexpr int PRESSURE_ID = 14;
|
static constexpr int PRESSURE_ID = 14;
|
||||||
static constexpr int ANGLE_ID = 15;
|
static constexpr int ANGLE_ID = 15;
|
||||||
static constexpr int CURRENCY_ID = 16;
|
static constexpr int CURRENCY_ID = 16;
|
||||||
|
static constexpr int GRAPHING_ID = 17;
|
||||||
// ^^^ THESE CONSTANTS SHOULD NEVER CHANGE ^^^
|
// ^^^ THESE CONSTANTS SHOULD NEVER CHANGE ^^^
|
||||||
|
|
||||||
|
wchar_t* towchar_t(int number)
|
||||||
|
{
|
||||||
|
auto wstr = to_wstring(number);
|
||||||
|
return _wcsdup(wstr.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsGraphingModeAvailable()
|
||||||
|
{
|
||||||
|
static bool supportGraph = Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath");
|
||||||
|
return supportGraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
Box<bool> ^ _isGraphingModeEnabledCached = nullptr;
|
||||||
|
bool IsGraphingModeEnabled()
|
||||||
|
{
|
||||||
|
if (!IsGraphingModeAvailable())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isGraphingModeEnabledCached != nullptr)
|
||||||
|
{
|
||||||
|
return _isGraphingModeEnabledCached->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
User ^ firstUser;
|
||||||
|
create_task(User::FindAllAsync(UserType::LocalUser)).then([&firstUser](IVectorView<User ^> ^ users) {
|
||||||
|
firstUser = users->GetAt(0); }).wait();
|
||||||
|
auto namedPolicyData = NamedPolicy::GetPolicyFromPathForUser(firstUser, L"Education", L"AllowGraphingCalculator");
|
||||||
|
_isGraphingModeEnabledCached = namedPolicyData->GetBoolean() == true;
|
||||||
|
|
||||||
|
return _isGraphingModeEnabledCached->Value;
|
||||||
|
}
|
||||||
|
|
||||||
// The order of items in this list determines the order of items in the menu.
|
// The order of items in this list determines the order of items in the menu.
|
||||||
static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = { NavCategoryInitializer{ ViewMode::Standard,
|
static const list<NavCategoryInitializer> s_categoryManifest = [] {
|
||||||
|
auto res = list<NavCategoryInitializer>{ NavCategoryInitializer{ ViewMode::Standard,
|
||||||
STANDARD_ID,
|
STANDARD_ID,
|
||||||
L"Standard",
|
L"Standard",
|
||||||
L"StandardMode",
|
L"StandardMode",
|
||||||
L"\uE8EF",
|
L"\uE8EF",
|
||||||
CategoryGroupType::Calculator,
|
CategoryGroupType::Calculator,
|
||||||
MyVirtualKey::Number1,
|
MyVirtualKey::Number1,
|
||||||
SUPPORTS_ALL },
|
L"1",
|
||||||
|
SUPPORTS_ALL,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Scientific,
|
NavCategoryInitializer{ ViewMode::Scientific,
|
||||||
SCIENTIFIC_ID,
|
SCIENTIFIC_ID,
|
||||||
L"Scientific",
|
L"Scientific",
|
||||||
|
@ -64,23 +100,49 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uF196",
|
L"\uF196",
|
||||||
CategoryGroupType::Calculator,
|
CategoryGroupType::Calculator,
|
||||||
MyVirtualKey::Number2,
|
MyVirtualKey::Number2,
|
||||||
SUPPORTS_ALL },
|
L"2",
|
||||||
NavCategoryInitializer{ ViewMode::Programmer,
|
SUPPORTS_ALL,
|
||||||
|
true } };
|
||||||
|
|
||||||
|
int currentIndex = 3;
|
||||||
|
bool supportGraphingCalculator = IsGraphingModeAvailable();
|
||||||
|
if (supportGraphingCalculator)
|
||||||
|
{
|
||||||
|
const bool isEnabled = IsGraphingModeEnabled();
|
||||||
|
res.push_back(NavCategoryInitializer{ ViewMode::Graphing,
|
||||||
|
GRAPHING_ID,
|
||||||
|
L"Graphing",
|
||||||
|
L"GraphingCalculatorMode",
|
||||||
|
L"\uF770",
|
||||||
|
CategoryGroupType::Calculator,
|
||||||
|
MyVirtualKey::Number3,
|
||||||
|
L"3",
|
||||||
|
SUPPORTS_ALL,
|
||||||
|
isEnabled });
|
||||||
|
++currentIndex;
|
||||||
|
}
|
||||||
|
res.insert(
|
||||||
|
res.end(),
|
||||||
|
{ NavCategoryInitializer{ ViewMode::Programmer,
|
||||||
PROGRAMMER_ID,
|
PROGRAMMER_ID,
|
||||||
L"Programmer",
|
L"Programmer",
|
||||||
L"ProgrammerMode",
|
L"ProgrammerMode",
|
||||||
L"\uECCE",
|
L"\uECCE",
|
||||||
CategoryGroupType::Calculator,
|
CategoryGroupType::Calculator,
|
||||||
MyVirtualKey::Number3,
|
supportGraphingCalculator ? MyVirtualKey::Number4 : MyVirtualKey::Number3,
|
||||||
SUPPORTS_ALL },
|
towchar_t(currentIndex++),
|
||||||
|
SUPPORTS_ALL,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Date,
|
NavCategoryInitializer{ ViewMode::Date,
|
||||||
DATE_ID,
|
DATE_ID,
|
||||||
L"Date",
|
L"Date",
|
||||||
L"DateCalculationMode",
|
L"DateCalculationMode",
|
||||||
L"\uE787",
|
L"\uE787",
|
||||||
CategoryGroupType::Calculator,
|
CategoryGroupType::Calculator,
|
||||||
MyVirtualKey::Number4,
|
supportGraphingCalculator ? MyVirtualKey::Number5 : MyVirtualKey::Number4,
|
||||||
SUPPORTS_ALL },
|
towchar_t(currentIndex++),
|
||||||
|
SUPPORTS_ALL,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Currency,
|
NavCategoryInitializer{ ViewMode::Currency,
|
||||||
CURRENCY_ID,
|
CURRENCY_ID,
|
||||||
L"Currency",
|
L"Currency",
|
||||||
|
@ -88,7 +150,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uEB0D",
|
L"\uEB0D",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Volume,
|
NavCategoryInitializer{ ViewMode::Volume,
|
||||||
VOLUME_ID,
|
VOLUME_ID,
|
||||||
L"Volume",
|
L"Volume",
|
||||||
|
@ -96,7 +160,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uF1AA",
|
L"\uF1AA",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Length,
|
NavCategoryInitializer{ ViewMode::Length,
|
||||||
LENGTH_ID,
|
LENGTH_ID,
|
||||||
L"Length",
|
L"Length",
|
||||||
|
@ -104,7 +170,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uECC6",
|
L"\uECC6",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Weight,
|
NavCategoryInitializer{ ViewMode::Weight,
|
||||||
WEIGHT_ID,
|
WEIGHT_ID,
|
||||||
L"Weight and Mass",
|
L"Weight and Mass",
|
||||||
|
@ -112,7 +180,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uF4C1",
|
L"\uF4C1",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Temperature,
|
NavCategoryInitializer{ ViewMode::Temperature,
|
||||||
TEMPERATURE_ID,
|
TEMPERATURE_ID,
|
||||||
L"Temperature",
|
L"Temperature",
|
||||||
|
@ -120,7 +190,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uE7A3",
|
L"\uE7A3",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
SUPPORTS_NEGATIVE },
|
nullptr,
|
||||||
|
SUPPORTS_NEGATIVE,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Energy,
|
NavCategoryInitializer{ ViewMode::Energy,
|
||||||
ENERGY_ID,
|
ENERGY_ID,
|
||||||
L"Energy",
|
L"Energy",
|
||||||
|
@ -128,7 +200,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uECAD",
|
L"\uECAD",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Area,
|
NavCategoryInitializer{ ViewMode::Area,
|
||||||
AREA_ID,
|
AREA_ID,
|
||||||
L"Area",
|
L"Area",
|
||||||
|
@ -136,7 +210,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uE809",
|
L"\uE809",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Speed,
|
NavCategoryInitializer{ ViewMode::Speed,
|
||||||
SPEED_ID,
|
SPEED_ID,
|
||||||
L"Speed",
|
L"Speed",
|
||||||
|
@ -144,7 +220,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uEADA",
|
L"\uEADA",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Time,
|
NavCategoryInitializer{ ViewMode::Time,
|
||||||
TIME_ID,
|
TIME_ID,
|
||||||
L"Time",
|
L"Time",
|
||||||
|
@ -152,7 +230,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uE917",
|
L"\uE917",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Power,
|
NavCategoryInitializer{ ViewMode::Power,
|
||||||
POWER_ID,
|
POWER_ID,
|
||||||
L"Power",
|
L"Power",
|
||||||
|
@ -160,7 +240,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uE945",
|
L"\uE945",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
SUPPORTS_NEGATIVE },
|
nullptr,
|
||||||
|
SUPPORTS_NEGATIVE,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Data,
|
NavCategoryInitializer{ ViewMode::Data,
|
||||||
DATA_ID,
|
DATA_ID,
|
||||||
L"Data",
|
L"Data",
|
||||||
|
@ -168,7 +250,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uF20F",
|
L"\uF20F",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Pressure,
|
NavCategoryInitializer{ ViewMode::Pressure,
|
||||||
PRESSURE_ID,
|
PRESSURE_ID,
|
||||||
L"Pressure",
|
L"Pressure",
|
||||||
|
@ -176,7 +260,9 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uEC4A",
|
L"\uEC4A",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
POSITIVE_ONLY },
|
nullptr,
|
||||||
|
POSITIVE_ONLY,
|
||||||
|
true },
|
||||||
NavCategoryInitializer{ ViewMode::Angle,
|
NavCategoryInitializer{ ViewMode::Angle,
|
||||||
ANGLE_ID,
|
ANGLE_ID,
|
||||||
L"Angle",
|
L"Angle",
|
||||||
|
@ -184,7 +270,11 @@ static constexpr array<const NavCategoryInitializer, 17> s_categoryManifest = {
|
||||||
L"\uF515",
|
L"\uF515",
|
||||||
CategoryGroupType::Converter,
|
CategoryGroupType::Converter,
|
||||||
MyVirtualKey::None,
|
MyVirtualKey::None,
|
||||||
SUPPORTS_NEGATIVE } };
|
nullptr,
|
||||||
|
SUPPORTS_NEGATIVE,
|
||||||
|
true } });
|
||||||
|
return res;
|
||||||
|
}();
|
||||||
|
|
||||||
// This function should only be used when storing the mode to app data.
|
// This function should only be used when storing the mode to app data.
|
||||||
int NavCategory::Serialize(ViewMode mode)
|
int NavCategory::Serialize(ViewMode mode)
|
||||||
|
@ -211,6 +301,14 @@ ViewMode NavCategory::Deserialize(Platform::Object ^ obj)
|
||||||
|
|
||||||
if (iter != s_categoryManifest.end())
|
if (iter != s_categoryManifest.end())
|
||||||
{
|
{
|
||||||
|
if (iter->viewMode == ViewMode::Graphing)
|
||||||
|
{
|
||||||
|
// check if the user is allowed to use this feature
|
||||||
|
if (!IsGraphingModeEnabled())
|
||||||
|
{
|
||||||
|
return ViewMode::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
return iter->viewMode;
|
return iter->viewMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,11 +324,23 @@ bool NavCategory::IsValidViewMode(ViewMode mode)
|
||||||
return iter != s_categoryManifest.end();
|
return iter != s_categoryManifest.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NavCategory::IsViewModeEnabled(ViewMode mode)
|
||||||
|
{
|
||||||
|
auto iter =
|
||||||
|
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode && initializer.isEnabled; });
|
||||||
|
|
||||||
|
return iter != s_categoryManifest.end();
|
||||||
|
}
|
||||||
|
|
||||||
bool NavCategory::IsCalculatorViewMode(ViewMode mode)
|
bool NavCategory::IsCalculatorViewMode(ViewMode mode)
|
||||||
{
|
{
|
||||||
// Historically, Date Calculator is not a Calculator mode
|
// Historically, Calculator modes are Standard, Scientific, and Programmer.
|
||||||
// even though it is in the Calculator category.
|
return !IsDateCalculatorViewMode(mode) && !IsGraphingCalculatorViewMode(mode) && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator);
|
||||||
return !IsDateCalculatorViewMode(mode) && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator);
|
}
|
||||||
|
|
||||||
|
bool NavCategory::IsGraphingCalculatorViewMode(ViewMode mode)
|
||||||
|
{
|
||||||
|
return mode == ViewMode::Graphing;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavCategory::IsDateCalculatorViewMode(ViewMode mode)
|
bool NavCategory::IsDateCalculatorViewMode(ViewMode mode)
|
||||||
|
@ -389,10 +499,12 @@ NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupIniti
|
||||||
categoryName,
|
categoryName,
|
||||||
categoryAutomationName,
|
categoryAutomationName,
|
||||||
StringReference(categoryInitializer.glyph),
|
StringReference(categoryInitializer.glyph),
|
||||||
resProvider->GetResourceString(nameResourceKey + "AccessKey"),
|
categoryInitializer.accessKey != nullptr ? ref new String(categoryInitializer.accessKey)
|
||||||
|
: resProvider->GetResourceString(nameResourceKey + "AccessKey"),
|
||||||
groupMode,
|
groupMode,
|
||||||
categoryInitializer.viewMode,
|
categoryInitializer.viewMode,
|
||||||
categoryInitializer.supportsNegative));
|
categoryInitializer.supportsNegative,
|
||||||
|
categoryInitializer.isEnabled));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,29 +519,12 @@ IObservableVector<NavCategoryGroup ^> ^ NavCategoryGroup::CreateMenuOptions()
|
||||||
|
|
||||||
NavCategoryGroup ^ NavCategoryGroup::CreateCalculatorCategory()
|
NavCategoryGroup ^ NavCategoryGroup::CreateCalculatorCategory()
|
||||||
{
|
{
|
||||||
return ref new NavCategoryGroup(s_categoryGroupManifest.at(0));
|
return ref new NavCategoryGroup(
|
||||||
|
NavCategoryGroupInitializer{ CategoryGroupType::Calculator, L"CalculatorModeTextCaps", L"CalculatorModeText", L"CalculatorModePluralText" });
|
||||||
}
|
}
|
||||||
|
|
||||||
NavCategoryGroup ^ NavCategoryGroup::CreateConverterCategory()
|
NavCategoryGroup ^ NavCategoryGroup::CreateConverterCategory()
|
||||||
{
|
{
|
||||||
return ref new NavCategoryGroup(s_categoryGroupManifest.at(1));
|
return ref new NavCategoryGroup(
|
||||||
}
|
NavCategoryGroupInitializer{ CategoryGroupType::Converter, L"ConverterModeTextCaps", L"ConverterModeText", L"ConverterModePluralText" });
|
||||||
|
|
||||||
vector<NavCategoryInitializer> NavCategoryGroup::GetInitializerCategoryGroup(CategoryGroupType groupType)
|
|
||||||
{
|
|
||||||
vector<NavCategoryInitializer> initializers{};
|
|
||||||
copy_if(begin(s_categoryManifest), end(s_categoryManifest), back_inserter(initializers), [groupType](const NavCategoryInitializer& initializer) {
|
|
||||||
return initializer.groupType == groupType;
|
|
||||||
});
|
|
||||||
|
|
||||||
return initializers;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ^ NavCategoryGroup::GetHeaderResourceKey(CategoryGroupType type)
|
|
||||||
{
|
|
||||||
auto iter = find_if(begin(s_categoryGroupManifest), end(s_categoryGroupManifest), [type](const NavCategoryGroupInitializer& initializer) {
|
|
||||||
return initializer.type == type;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (iter != s_categoryGroupManifest.end()) ? StringReference(iter->headerResourceKey) : nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,8 @@ namespace CalculatorApp
|
||||||
Data = 13,
|
Data = 13,
|
||||||
Pressure = 14,
|
Pressure = 14,
|
||||||
Angle = 15,
|
Angle = 15,
|
||||||
Currency = 16
|
Currency = 16,
|
||||||
|
Graphing = 17
|
||||||
};
|
};
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -66,7 +67,9 @@ namespace CalculatorApp
|
||||||
wchar_t const* glyph,
|
wchar_t const* glyph,
|
||||||
CategoryGroupType group,
|
CategoryGroupType group,
|
||||||
MyVirtualKey vKey,
|
MyVirtualKey vKey,
|
||||||
bool categorySupportsNegative)
|
wchar_t const* aKey,
|
||||||
|
bool categorySupportsNegative,
|
||||||
|
bool enabled)
|
||||||
: viewMode(mode)
|
: viewMode(mode)
|
||||||
, serializationId(id)
|
, serializationId(id)
|
||||||
, friendlyName(name)
|
, friendlyName(name)
|
||||||
|
@ -74,7 +77,9 @@ namespace CalculatorApp
|
||||||
, glyph(glyph)
|
, glyph(glyph)
|
||||||
, groupType(group)
|
, groupType(group)
|
||||||
, virtualKey(vKey)
|
, virtualKey(vKey)
|
||||||
|
, accessKey(aKey)
|
||||||
, supportsNegative(categorySupportsNegative)
|
, supportsNegative(categorySupportsNegative)
|
||||||
|
, isEnabled(enabled)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +90,9 @@ namespace CalculatorApp
|
||||||
const wchar_t* const glyph;
|
const wchar_t* const glyph;
|
||||||
const CategoryGroupType groupType;
|
const CategoryGroupType groupType;
|
||||||
const MyVirtualKey virtualKey;
|
const MyVirtualKey virtualKey;
|
||||||
|
const wchar_t* const accessKey;
|
||||||
const bool supportsNegative;
|
const bool supportsNegative;
|
||||||
|
const bool isEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -109,45 +116,17 @@ namespace CalculatorApp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OBSERVABLE_OBJECT();
|
OBSERVABLE_OBJECT();
|
||||||
|
PROPERTY_R(Platform::String ^, Name);
|
||||||
|
PROPERTY_R(Platform::String ^, AutomationName);
|
||||||
|
PROPERTY_R(Platform::String ^, Glyph);
|
||||||
|
PROPERTY_R(ViewMode, Mode);
|
||||||
|
PROPERTY_R(Platform::String ^, AccessKey);
|
||||||
|
PROPERTY_R(bool, SupportsNegative);
|
||||||
|
PROPERTY_R(bool, IsEnabled);
|
||||||
|
|
||||||
property Platform::String
|
property Platform::String
|
||||||
^ Name { Platform::String ^ get() { return m_name; } }
|
^ AutomationId { Platform::String ^ get() { return m_Mode.ToString(); } }
|
||||||
|
|
||||||
property Platform::String
|
|
||||||
^ AutomationName { Platform::String ^ get() { return m_automationName; } }
|
|
||||||
|
|
||||||
property Platform::String
|
|
||||||
^ Glyph { Platform::String ^ get() { return m_glyph; } }
|
|
||||||
|
|
||||||
property int Position
|
|
||||||
{
|
|
||||||
int get()
|
|
||||||
{
|
|
||||||
return m_position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property ViewMode Mode
|
|
||||||
{
|
|
||||||
ViewMode get()
|
|
||||||
{
|
|
||||||
return m_viewMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property Platform::String
|
|
||||||
^ AutomationId { Platform::String ^ get() { return m_viewMode.ToString(); } }
|
|
||||||
|
|
||||||
property Platform::String
|
|
||||||
^ AccessKey { Platform::String ^ get() { return m_accessKey; } }
|
|
||||||
|
|
||||||
property bool SupportsNegative
|
|
||||||
{
|
|
||||||
bool get()
|
|
||||||
{
|
|
||||||
return m_supportsNegative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For saving/restoring last mode used.
|
// For saving/restoring last mode used.
|
||||||
static int Serialize(ViewMode mode);
|
static int Serialize(ViewMode mode);
|
||||||
|
@ -155,7 +134,9 @@ namespace CalculatorApp
|
||||||
static ViewMode GetViewModeForFriendlyName(Platform::String ^ name);
|
static ViewMode GetViewModeForFriendlyName(Platform::String ^ name);
|
||||||
|
|
||||||
static bool IsValidViewMode(ViewMode mode);
|
static bool IsValidViewMode(ViewMode mode);
|
||||||
|
static bool IsViewModeEnabled(ViewMode mode);
|
||||||
static bool IsCalculatorViewMode(ViewMode mode);
|
static bool IsCalculatorViewMode(ViewMode mode);
|
||||||
|
static bool IsGraphingCalculatorViewMode(ViewMode mode);
|
||||||
static bool IsDateCalculatorViewMode(ViewMode mode);
|
static bool IsDateCalculatorViewMode(ViewMode mode);
|
||||||
static bool IsConverterViewMode(ViewMode mode);
|
static bool IsConverterViewMode(ViewMode mode);
|
||||||
|
|
||||||
|
@ -178,16 +159,17 @@ namespace CalculatorApp
|
||||||
Platform::String ^ accessKey,
|
Platform::String ^ accessKey,
|
||||||
Platform::String ^ mode,
|
Platform::String ^ mode,
|
||||||
ViewMode viewMode,
|
ViewMode viewMode,
|
||||||
bool supportsNegative)
|
bool supportsNegative,
|
||||||
: m_name(name)
|
bool isEnabled)
|
||||||
, m_automationName(automationName)
|
: m_Name(name)
|
||||||
, m_glyph(glyph)
|
, m_AutomationName(automationName)
|
||||||
, m_accessKey(accessKey)
|
, m_Glyph(glyph)
|
||||||
, m_mode(mode)
|
, m_AccessKey(accessKey)
|
||||||
, m_viewMode(viewMode)
|
, m_modeString(mode)
|
||||||
, m_supportsNegative(supportsNegative)
|
, m_Mode(viewMode)
|
||||||
|
, m_SupportsNegative(supportsNegative)
|
||||||
|
, m_IsEnabled(isEnabled)
|
||||||
{
|
{
|
||||||
m_position = NavCategory::GetPosition(m_viewMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<MyVirtualKey> GetCategoryAcceleratorKeys();
|
static std::vector<MyVirtualKey> GetCategoryAcceleratorKeys();
|
||||||
|
@ -195,14 +177,7 @@ namespace CalculatorApp
|
||||||
private:
|
private:
|
||||||
static bool IsModeInCategoryGroup(ViewMode mode, CategoryGroupType groupType);
|
static bool IsModeInCategoryGroup(ViewMode mode, CategoryGroupType groupType);
|
||||||
|
|
||||||
ViewMode m_viewMode;
|
Platform::String ^ m_modeString;
|
||||||
Platform::String ^ m_name;
|
|
||||||
Platform::String ^ m_automationName;
|
|
||||||
Platform::String ^ m_glyph;
|
|
||||||
Platform::String ^ m_accessKey;
|
|
||||||
Platform::String ^ m_mode;
|
|
||||||
int m_position;
|
|
||||||
bool m_supportsNegative;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[Windows::UI::Xaml::Data::Bindable] public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
[Windows::UI::Xaml::Data::Bindable] public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
||||||
|
@ -216,15 +191,11 @@ namespace CalculatorApp
|
||||||
|
|
||||||
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
|
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
|
||||||
|
|
||||||
static Platform::String ^ GetHeaderResourceKey(CategoryGroupType type);
|
|
||||||
|
|
||||||
internal : static NavCategoryGroup ^ CreateCalculatorCategory();
|
internal : static NavCategoryGroup ^ CreateCalculatorCategory();
|
||||||
static NavCategoryGroup ^ CreateConverterCategory();
|
static NavCategoryGroup ^ CreateConverterCategory();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
|
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
|
||||||
|
|
||||||
static std::vector<NavCategoryInitializer> GetInitializerCategoryGroup(CategoryGroupType groupType);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
// Licensed under the MIT License.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
|
||||||
{
|
|
||||||
constexpr int64_t WINEVENT_KEYWORD_RESPONSE_TIME = 0x1000000000000;
|
|
||||||
|
|
||||||
// RAII wrapper that automatically sends the Stop event when the class gets destructed.
|
|
||||||
class TraceActivity
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TraceActivity()
|
|
||||||
: m_channel(nullptr)
|
|
||||||
, m_activity(nullptr)
|
|
||||||
, m_fields(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceActivity(
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingChannel channel,
|
|
||||||
std::wstring_view activityName,
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingFields fields)
|
|
||||||
: m_channel(channel)
|
|
||||||
, m_activityName(activityName)
|
|
||||||
, m_fields(fields)
|
|
||||||
, m_activity(nullptr)
|
|
||||||
{
|
|
||||||
// Write the activity's START event. Note that you must not specify keyword
|
|
||||||
// or level for START and STOP events because they always use the activity's
|
|
||||||
// keyword and level.
|
|
||||||
m_activity = m_channel.StartActivity(
|
|
||||||
m_activityName,
|
|
||||||
m_fields,
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingLevel::Verbose,
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingOptions(WINEVENT_KEYWORD_RESPONSE_TIME));
|
|
||||||
}
|
|
||||||
|
|
||||||
~TraceActivity()
|
|
||||||
{
|
|
||||||
if (m_activity != nullptr)
|
|
||||||
{
|
|
||||||
// Write the activity's STOP event.
|
|
||||||
m_activity.StopActivity(m_activityName, m_fields);
|
|
||||||
m_activity = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::wstring m_activityName;
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingChannel m_channel;
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingFields m_fields;
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingActivity m_activity;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -8,15 +8,15 @@
|
||||||
|
|
||||||
using namespace CalculatorApp;
|
using namespace CalculatorApp;
|
||||||
using namespace CalculatorApp::Common;
|
using namespace CalculatorApp::Common;
|
||||||
|
using namespace TraceLogging;
|
||||||
using namespace Concurrency;
|
using namespace Concurrency;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace winrt;
|
using namespace Windows::Foundation;
|
||||||
using namespace winrt::Windows::Foundation;
|
using namespace Windows::Foundation::Diagnostics;
|
||||||
using namespace winrt::Windows::Foundation::Diagnostics;
|
using namespace Windows::Globalization;
|
||||||
using namespace winrt::Windows::Globalization;
|
using namespace Windows::Globalization::DateTimeFormatting;
|
||||||
using namespace winrt::Windows::Globalization::DateTimeFormatting;
|
using namespace Windows::System::UserProfile;
|
||||||
using namespace winrt::Windows::System::UserProfile;
|
|
||||||
|
|
||||||
namespace CalculatorApp
|
namespace CalculatorApp
|
||||||
{
|
{
|
||||||
|
@ -35,36 +35,23 @@ namespace CalculatorApp
|
||||||
constexpr auto EVENT_NAME_VISUAL_STATE_CHANGED = L"VisualStateChanged";
|
constexpr auto EVENT_NAME_VISUAL_STATE_CHANGED = L"VisualStateChanged";
|
||||||
constexpr auto EVENT_NAME_CONVERTER_INPUT_RECEIVED = L"ConverterInputReceived";
|
constexpr auto EVENT_NAME_CONVERTER_INPUT_RECEIVED = L"ConverterInputReceived";
|
||||||
constexpr auto EVENT_NAME_INPUT_PASTED = L"InputPasted";
|
constexpr auto EVENT_NAME_INPUT_PASTED = L"InputPasted";
|
||||||
|
constexpr auto EVENT_NAME_SHOW_HIDE_BUTTON_CLICKED = L"ShowHideButtonClicked";
|
||||||
|
constexpr auto EVENT_NAME_GRAPH_BUTTON_CLICKED = L"GraphButtonClicked";
|
||||||
|
constexpr auto EVENT_NAME_GRAPH_LINE_STYLE_CHANGED = L"GraphLineStyleChanged";
|
||||||
|
constexpr auto EVENT_NAME_VARIABLE_CHANGED = L"VariableChanged";
|
||||||
|
constexpr auto EVENT_NAME_VARIABLE_SETTING_CHANGED = L"VariableSettingChanged";
|
||||||
|
constexpr auto EVENT_NAME_GRAPH_SETTINGS_CHANGED = L"GraphSettingsChanged";
|
||||||
|
constexpr auto EVENT_NAME_GRAPH_THEME = L"GraphTheme";
|
||||||
|
|
||||||
constexpr auto EVENT_NAME_EXCEPTION = L"Exception";
|
constexpr auto EVENT_NAME_EXCEPTION = L"Exception";
|
||||||
|
|
||||||
constexpr auto PDT_PRIVACY_DATA_TAG = L"PartA_PrivTags";
|
constexpr auto CALC_MODE = L"CalcMode";
|
||||||
constexpr auto PDT_PRODUCT_AND_SERVICE_USAGE = 0x0000'0000'0200'0000u;
|
constexpr auto GRAPHING_MODE = L"Graphing";
|
||||||
|
|
||||||
#ifdef SEND_DIAGNOSTICS
|
|
||||||
// c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords
|
|
||||||
// c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords
|
|
||||||
constexpr int64_t MICROSOFT_KEYWORD_LEVEL_1 = 0x0000800000000000; // Bit 47
|
|
||||||
constexpr int64_t MICROSOFT_KEYWORD_LEVEL_2 = 0x0000400000000000; // Bit 46
|
|
||||||
constexpr int64_t MICROSOFT_KEYWORD_LEVEL_3 = 0x0000200000000000; // Bit 45
|
|
||||||
#else
|
|
||||||
// define all Keyword options as 0 when we do not want to upload app diagnostics
|
|
||||||
constexpr int64_t MICROSOFT_KEYWORD_LEVEL_1 = 0;
|
|
||||||
constexpr int64_t MICROSOFT_KEYWORD_LEVEL_2 = 0;
|
|
||||||
constexpr int64_t MICROSOFT_KEYWORD_LEVEL_3 = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma region TraceLogger setup and cleanup
|
#pragma region TraceLogger setup and cleanup
|
||||||
|
|
||||||
TraceLogger::TraceLogger()
|
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 })
|
|
||||||
, // Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0}
|
|
||||||
m_appLaunchActivity{ nullptr }
|
|
||||||
{
|
{
|
||||||
CoCreateGuid(&sessionGuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceLogger ^ TraceLogger::GetInstance()
|
TraceLogger ^ TraceLogger::GetInstance()
|
||||||
|
@ -73,33 +60,6 @@ namespace CalculatorApp
|
||||||
return s_selfInstance;
|
return s_selfInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraceLogger::GetTraceLoggingProviderEnabled()
|
|
||||||
{
|
|
||||||
return g_calculatorProvider.Enabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma region Tracing methods
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TraceLogger::LogLevel3Event(wstring_view eventName, LoggingFields fields)
|
|
||||||
{
|
|
||||||
g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_3));
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<TraceActivity> TraceLogger::CreateTraceActivity(wstring_view eventName, LoggingFields fields)
|
|
||||||
{
|
|
||||||
return make_unique<TraceActivity>(g_calculatorProvider, eventName, fields);
|
|
||||||
}
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
// return true if windowId is logged once else return false
|
// return true if windowId is logged once else return false
|
||||||
bool TraceLogger::IsWindowIdInLog(int windowId)
|
bool TraceLogger::IsWindowIdInLog(int windowId)
|
||||||
{
|
{
|
||||||
|
@ -116,18 +76,12 @@ namespace CalculatorApp
|
||||||
|
|
||||||
void TraceLogger::LogVisualStateChanged(ViewMode mode, String ^ state, bool isAlwaysOnTop)
|
void TraceLogger::LogVisualStateChanged(ViewMode mode, String ^ state, bool isAlwaysOnTop)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoggingFields fields{};
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
fields->AddString(StringReference(L"VisualState"), state);
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
fields->AddBoolean(StringReference(L"IsAlwaysOnTop"), isAlwaysOnTop);
|
||||||
fields.AddString(L"VisualState", state->Data());
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VISUAL_STATE_CHANGED), fields);
|
||||||
fields.AddBoolean(L"IsAlwaysOnTop", isAlwaysOnTop);
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_VISUAL_STATE_CHANGED, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogWindowCreated(ViewMode mode, int windowId)
|
void TraceLogger::LogWindowCreated(ViewMode mode, int windowId)
|
||||||
|
@ -138,122 +92,69 @@ namespace CalculatorApp
|
||||||
windowIdLog.push_back(windowId);
|
windowIdLog.push_back(windowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
|
fields->AddUInt64(StringReference(L"NumOfOpenWindows"), currentWindowCount);
|
||||||
LoggingFields fields{};
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_WINDOW_ON_CREATED), fields);
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
fields.AddUInt64(L"NumOfOpenWindows", currentWindowCount);
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_WINDOW_ON_CREATED, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogModeChange(ViewMode mode)
|
void TraceLogger::LogModeChange(ViewMode mode)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (NavCategory::IsValidViewMode(mode))
|
if (NavCategory::IsValidViewMode(mode))
|
||||||
{
|
{
|
||||||
LoggingFields fields{};
|
auto fields = ref new LoggingFields();
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
;
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MODE_CHANGED), fields);
|
||||||
LogLevel2Event(EVENT_NAME_MODE_CHANGED, fields);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex)
|
void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
{
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
return;
|
fields->AddInt32(StringReference(L"HistoryListSize"), historyListSize);
|
||||||
}
|
fields->AddInt32(StringReference(L"HistoryItemIndex"), loadedIndex);
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_HISTORY_ITEM_LOAD), fields);
|
||||||
LoggingFields fields{};
|
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
fields.AddInt32(L"HistoryListSize", historyListSize);
|
|
||||||
fields.AddInt32(L"HistoryItemIndex", loadedIndex);
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_HISTORY_ITEM_LOAD, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex)
|
void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
{
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
return;
|
fields->AddInt32(StringReference(L"MemoryListSize"), memoryListSize);
|
||||||
}
|
fields->AddInt32(StringReference(L"MemoryItemIndex"), loadedIndex);
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MEMORY_ITEM_LOAD), fields);
|
||||||
LoggingFields fields{};
|
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
fields.AddInt32(L"MemoryListSize", memoryListSize);
|
|
||||||
fields.AddInt32(L"MemoryItemIndex", loadedIndex);
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_MEMORY_ITEM_LOAD, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogError(ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString)
|
void TraceLogger::LogError(ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
|
fields->AddString(StringReference(L"FunctionName"), functionName);
|
||||||
LoggingFields fields{};
|
fields->AddString(StringReference(L"Message"), errorString);
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
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)
|
void TraceLogger::LogStandardException(ViewMode mode, wstring_view functionName, const exception& e)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
|
fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data()));
|
||||||
LoggingFields fields{};
|
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
fields.AddString(L"FunctionName", functionName);
|
|
||||||
wstringstream exceptionMessage;
|
wstringstream exceptionMessage;
|
||||||
exceptionMessage << e.what();
|
exceptionMessage << e.what();
|
||||||
fields.AddString(L"Message", exceptionMessage.str());
|
fields->AddString(StringReference(L"Message"), StringReference(exceptionMessage.str().data()));
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
|
||||||
LogLevel2Event(EVENT_NAME_EXCEPTION, fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TraceLogger::LogWinRTException(ViewMode mode, wstring_view functionName, hresult_error const& e)
|
|
||||||
{
|
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
LoggingFields fields{};
|
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
fields.AddString(L"FunctionName", functionName);
|
|
||||||
fields.AddString(L"Message", e.message());
|
|
||||||
fields.AddInt32(L"HRESULT", e.code());
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_EXCEPTION, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogPlatformException(ViewMode mode, wstring_view functionName, Platform::Exception ^ e)
|
void TraceLogger::LogPlatformException(ViewMode mode, wstring_view functionName, Platform::Exception ^ e)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
|
fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data()));
|
||||||
LoggingFields fields{};
|
fields->AddString(StringReference(L"Message"), e->Message);
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
fields->AddInt32(StringReference(L"HRESULT"), e->HResult);
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
|
||||||
fields.AddString(L"FunctionName", functionName);
|
|
||||||
fields.AddString(L"Message", e->Message->Data());
|
|
||||||
fields.AddInt32(L"HRESULT", e->HResult);
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_EXCEPTION, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::UpdateButtonUsage(NumbersAndOperatorsEnum button, ViewMode mode)
|
void TraceLogger::UpdateButtonUsage(NumbersAndOperatorsEnum button, ViewMode mode)
|
||||||
|
@ -305,9 +206,6 @@ namespace CalculatorApp
|
||||||
|
|
||||||
void TraceLogger::LogButtonUsage()
|
void TraceLogger::LogButtonUsage()
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Writer lock for the buttonLog resource
|
// Writer lock for the buttonLog resource
|
||||||
reader_writer_lock::scoped_lock lock(s_traceLoggerLock);
|
reader_writer_lock::scoped_lock lock(s_traceLoggerLock);
|
||||||
|
|
||||||
|
@ -330,11 +228,9 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LoggingFields fields{};
|
auto fields = ref new LoggingFields();
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
fields->AddString(StringReference(L"ButtonUsage"), buttonUsageString);
|
||||||
fields.AddString(L"ButtonUsage", buttonUsageString->Data());
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_BUTTON_USAGE), fields);
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_BUTTON_USAGE, fields);
|
|
||||||
|
|
||||||
buttonLog.clear();
|
buttonLog.clear();
|
||||||
}
|
}
|
||||||
|
@ -342,46 +238,89 @@ namespace CalculatorApp
|
||||||
void TraceLogger::LogDateCalculationModeUsed(bool AddSubtractMode)
|
void TraceLogger::LogDateCalculationModeUsed(bool AddSubtractMode)
|
||||||
{
|
{
|
||||||
const wchar_t* calculationType = AddSubtractMode ? L"AddSubtractMode" : L"DateDifferenceMode";
|
const wchar_t* calculationType = AddSubtractMode ? L"AddSubtractMode" : L"DateDifferenceMode";
|
||||||
LoggingFields fields{};
|
auto fields = ref new LoggingFields();
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(ViewMode::Date));
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(ViewMode::Date)->Data());
|
fields->AddString(StringReference(L"CalculationType"), StringReference(calculationType));
|
||||||
fields.AddString(L"CalculationType", calculationType);
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_DATE_CALCULATION_MODE_USED), fields);
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_DATE_CALCULATION_MODE_USED, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogConverterInputReceived(ViewMode mode)
|
void TraceLogger::LogConverterInputReceived(ViewMode mode)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_CONVERTER_INPUT_RECEIVED), fields);
|
||||||
LoggingFields fields{};
|
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data());
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_CONVERTER_INPUT_RECEIVED, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogNavBarOpened()
|
void TraceLogger::LogNavBarOpened()
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_NAV_BAR_OPENED), fields);
|
||||||
|
|
||||||
LoggingFields fields{};
|
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
|
||||||
LogLevel2Event(EVENT_NAME_NAV_BAR_OPENED, fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogInputPasted(ViewMode mode)
|
void TraceLogger::LogInputPasted(ViewMode mode)
|
||||||
{
|
{
|
||||||
if (!GetTraceLoggingProviderEnabled())
|
auto fields = ref new LoggingFields();
|
||||||
return;
|
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_INPUT_PASTED), fields);
|
||||||
|
}
|
||||||
|
|
||||||
LoggingFields fields{};
|
void TraceLogger::LogShowHideButtonClicked(bool isHideButton)
|
||||||
fields.AddGuid(L"SessionGuid", sessionGuid);
|
{
|
||||||
fields.AddString(L"Mode", NavCategory::GetFriendlyName(mode)->Data());
|
auto fields = ref new LoggingFields();
|
||||||
fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE);
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
LogLevel2Event(EVENT_NAME_INPUT_PASTED, fields);
|
fields->AddBoolean(StringReference(L"IsHideButton"), isHideButton);
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_SHOW_HIDE_BUTTON_CLICKED), fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceLogger::LogGraphButtonClicked(GraphButton buttonName, GraphButtonValue buttonValue)
|
||||||
|
{
|
||||||
|
auto fields = ref new LoggingFields();
|
||||||
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
|
fields->AddInt16(StringReference(L"ButtonName"), static_cast<int16>(buttonName));
|
||||||
|
fields->AddInt16(StringReference(L"ButtonValue"), static_cast<int16>(buttonValue));
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_BUTTON_CLICKED), fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceLogger::LogGraphLineStyleChanged(LineStyleType style)
|
||||||
|
{
|
||||||
|
auto fields = ref new LoggingFields();
|
||||||
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
|
fields->AddInt16(StringReference(L"StyleType"), static_cast<int16>(style));
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_LINE_STYLE_CHANGED), fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceLogger::LogVariableChanged(String ^ inputChangedType, String ^ variableName)
|
||||||
|
{
|
||||||
|
auto fields = ref new LoggingFields();
|
||||||
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
|
fields->AddString(StringReference(L"InputChangedType"), inputChangedType);
|
||||||
|
fields->AddString(StringReference(L"VariableName"), variableName);
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VARIABLE_CHANGED), fields);
|
||||||
|
}
|
||||||
|
void TraceLogger::LogVariableSettingsChanged(String ^ setting)
|
||||||
|
{
|
||||||
|
auto fields = ref new LoggingFields();
|
||||||
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
|
fields->AddString(StringReference(L"SettingChanged"), setting);
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VARIABLE_SETTING_CHANGED), fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceLogger::LogGraphSettingsChanged(GraphSettingsType settingType, String ^ settingValue)
|
||||||
|
{
|
||||||
|
auto fields = ref new LoggingFields();
|
||||||
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
|
fields->AddInt16(L"SettingType", static_cast<int16>(settingType));
|
||||||
|
fields->AddString(L"SettingValue", settingValue);
|
||||||
|
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_SETTINGS_CHANGED), fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceLogger::LogGraphTheme(String ^ graphTheme)
|
||||||
|
{
|
||||||
|
auto fields = ref new LoggingFields();
|
||||||
|
fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE));
|
||||||
|
fields->AddString(L"GraphTheme", graphTheme);
|
||||||
|
|
||||||
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_THEME), fields);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CalcManager/Command.h"
|
|
||||||
#include "TraceActivity.h"
|
|
||||||
#include "NavCategory.h"
|
#include "NavCategory.h"
|
||||||
#include "CalculatorButtonUser.h"
|
#include "CalculatorButtonUser.h"
|
||||||
|
|
||||||
static const int maxFunctionSize = (int)CalculationManager::Command::CommandBINEDITEND;
|
|
||||||
|
|
||||||
// A trace logging provider can only be instantiated and registered once per module.
|
// A trace logging provider can only be instantiated and registered once per module.
|
||||||
// This class implements a singleton model ensure that only one instance is created.
|
// This class implements a singleton model ensure that only one instance is created.
|
||||||
namespace CalculatorApp
|
namespace CalculatorApp
|
||||||
|
@ -28,12 +24,44 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public
|
public enum class GraphSettingsType
|
||||||
ref class TraceLogger sealed
|
{
|
||||||
|
Grid,
|
||||||
|
TrigUnits,
|
||||||
|
Theme
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum class GraphButton
|
||||||
|
{
|
||||||
|
StylePicker,
|
||||||
|
RemoveFunction,
|
||||||
|
ActiveTracingChecked,
|
||||||
|
ActiveTracingUnchecked,
|
||||||
|
GraphSettings,
|
||||||
|
Share,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
|
GraphView
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum class GraphButtonValue
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
AutomaticBestFit,
|
||||||
|
ManualAdjustment
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum class LineStyleType
|
||||||
|
{
|
||||||
|
Color,
|
||||||
|
Pattern
|
||||||
|
};
|
||||||
|
|
||||||
|
public ref class TraceLogger sealed
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static TraceLogger ^ GetInstance();
|
static TraceLogger ^ GetInstance();
|
||||||
bool GetTraceLoggingProviderEnabled();
|
|
||||||
void LogModeChange(CalculatorApp::Common::ViewMode mode);
|
void LogModeChange(CalculatorApp::Common::ViewMode mode);
|
||||||
void LogHistoryItemLoad(CalculatorApp::Common::ViewMode mode, int historyListSize, int loadedIndex);
|
void LogHistoryItemLoad(CalculatorApp::Common::ViewMode mode, int historyListSize, int loadedIndex);
|
||||||
void LogMemoryItemLoad(CalculatorApp::Common::ViewMode mode, int memoryListSize, int loadedIndex);
|
void LogMemoryItemLoad(CalculatorApp::Common::ViewMode mode, int memoryListSize, int loadedIndex);
|
||||||
|
@ -48,9 +76,15 @@ public
|
||||||
void LogConverterInputReceived(CalculatorApp::Common::ViewMode mode);
|
void LogConverterInputReceived(CalculatorApp::Common::ViewMode mode);
|
||||||
void LogNavBarOpened();
|
void LogNavBarOpened();
|
||||||
void LogError(CalculatorApp::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString);
|
void LogError(CalculatorApp::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString);
|
||||||
internal :
|
void LogShowHideButtonClicked(bool isHideButton);
|
||||||
|
void LogGraphButtonClicked(GraphButton buttonName, GraphButtonValue buttonValue);
|
||||||
|
void LogGraphLineStyleChanged(LineStyleType style);
|
||||||
|
void LogVariableChanged(Platform::String ^ inputChangedType, Platform::String ^ variableName);
|
||||||
|
void LogVariableSettingsChanged(Platform::String ^ setting);
|
||||||
|
void LogGraphSettingsChanged(GraphSettingsType settingsType, Platform::String ^ settingValue);
|
||||||
|
void LogGraphTheme(Platform::String ^ graphTheme);
|
||||||
|
internal:
|
||||||
void LogStandardException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ const std::exception& e);
|
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 LogPlatformException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ Platform::Exception ^ e);
|
||||||
void LogInputPasted(CalculatorApp::Common::ViewMode mode);
|
void LogInputPasted(CalculatorApp::Common::ViewMode mode);
|
||||||
|
|
||||||
|
@ -58,24 +92,8 @@ public
|
||||||
// Create an instance of TraceLogger
|
// Create an instance of TraceLogger
|
||||||
TraceLogger();
|
TraceLogger();
|
||||||
|
|
||||||
// As mentioned in Microsoft's Privacy Statement(https://privacy.microsoft.com/en-US/privacystatement#maindiagnosticsmodule),
|
|
||||||
// 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);
|
|
||||||
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<TraceActivity> CreateTraceActivity(std::wstring_view activityName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields);
|
|
||||||
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingChannel g_calculatorProvider;
|
|
||||||
|
|
||||||
std::vector<ButtonLog> buttonLog;
|
std::vector<ButtonLog> buttonLog;
|
||||||
std::vector<int> windowIdLog;
|
std::vector<int> windowIdLog;
|
||||||
|
|
||||||
GUID sessionGuid;
|
|
||||||
uint64 currentWindowCount = 0;
|
uint64 currentWindowCount = 0;
|
||||||
|
|
||||||
winrt::Windows::Foundation::Diagnostics::LoggingActivity m_appLaunchActivity;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,17 @@
|
||||||
using namespace CalculatorApp;
|
using namespace CalculatorApp;
|
||||||
using namespace CalculatorApp::Common;
|
using namespace CalculatorApp::Common;
|
||||||
using namespace concurrency;
|
using namespace concurrency;
|
||||||
|
using namespace Graphing::Renderer;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
using namespace Windows::ApplicationModel::Resources;
|
using namespace Windows::ApplicationModel::Resources;
|
||||||
using namespace Windows::Storage::Streams;
|
using namespace Windows::Storage::Streams;
|
||||||
|
using namespace Windows::UI;
|
||||||
using namespace Windows::UI::Core;
|
using namespace Windows::UI::Core;
|
||||||
using namespace Windows::UI::ViewManagement;
|
using namespace Windows::UI::ViewManagement;
|
||||||
using namespace Windows::UI::Xaml;
|
using namespace Windows::UI::Xaml;
|
||||||
|
using namespace Windows::UI::Xaml::Media;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Storage;
|
using namespace Windows::Storage;
|
||||||
|
|
||||||
|
@ -34,17 +37,6 @@ void Utils::IFTPlatformException(HRESULT hr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String ^ Utils::GetStringValue(String ^ input)
|
|
||||||
{
|
|
||||||
// Remove first and last " characters
|
|
||||||
if (input->Length() >= 3)
|
|
||||||
{
|
|
||||||
wstring out(input->Begin() + 1, input->End() - 1);
|
|
||||||
return ref new String(out.c_str());
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Utils::GetDoubleFromWstring(wstring input)
|
double Utils::GetDoubleFromWstring(wstring input)
|
||||||
{
|
{
|
||||||
constexpr wchar_t unWantedChars[] = { L' ', L',', 8234, 8235, 8236, 8237 };
|
constexpr wchar_t unWantedChars[] = { L' ', L',', 8234, 8235, 8236, 8237 };
|
||||||
|
@ -80,67 +72,6 @@ bool Utils::IsLastCharacterTarget(_In_ wstring const& input, _In_ wchar_t target
|
||||||
return !input.empty() && input.back() == target;
|
return !input.empty() && input.back() == target;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utils::SerializeCommandsAndTokens(
|
|
||||||
_In_ shared_ptr<vector<pair<wstring, int>>> const& tokens,
|
|
||||||
_In_ shared_ptr<vector<shared_ptr<IExpressionCommand>>> const& commands,
|
|
||||||
DataWriter ^ writer)
|
|
||||||
{
|
|
||||||
// Save the size of the commands vector
|
|
||||||
writer->WriteUInt32(static_cast<unsigned int>(commands->size()));
|
|
||||||
|
|
||||||
SerializeCommandVisitor cmdVisitor(writer);
|
|
||||||
for (const auto& exprCmd : *commands)
|
|
||||||
{
|
|
||||||
CalculationManager::CommandType commandType = exprCmd->GetCommandType();
|
|
||||||
writer->WriteInt32(static_cast<int>(commandType));
|
|
||||||
exprCmd->Accept(cmdVisitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->WriteUInt32(static_cast<unsigned int>(tokens->size()));
|
|
||||||
|
|
||||||
for (const auto& eachToken : *tokens)
|
|
||||||
{
|
|
||||||
auto stringData = ref new Platform::String(eachToken.first.c_str());
|
|
||||||
auto intData = eachToken.second;
|
|
||||||
writer->WriteUInt32(writer->MeasureString(stringData));
|
|
||||||
writer->WriteString(stringData);
|
|
||||||
writer->WriteInt32(intData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const shared_ptr<vector<shared_ptr<IExpressionCommand>>> Utils::DeserializeCommands(DataReader ^ reader)
|
|
||||||
{
|
|
||||||
auto commandVector = make_shared<vector<shared_ptr<IExpressionCommand>>>();
|
|
||||||
auto commandVectorSize = reader->ReadUInt32();
|
|
||||||
|
|
||||||
CommandDeserializer cmdDeserializer(reader);
|
|
||||||
for (unsigned int i = 0; i < commandVectorSize; ++i)
|
|
||||||
{
|
|
||||||
auto commandTypeInt = reader->ReadInt32();
|
|
||||||
CalculationManager::CommandType commandType = static_cast<CalculationManager::CommandType>(commandTypeInt);
|
|
||||||
shared_ptr<IExpressionCommand> exprCmd = cmdDeserializer.Deserialize(commandType);
|
|
||||||
commandVector->push_back(exprCmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return commandVector;
|
|
||||||
}
|
|
||||||
|
|
||||||
const shared_ptr<vector<pair<wstring, int>>> Utils::DeserializeTokens(DataReader ^ reader)
|
|
||||||
{
|
|
||||||
auto tokenVector = make_shared<vector<pair<wstring, int>>>();
|
|
||||||
auto tokensSize = reader->ReadUInt32();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < tokensSize; ++i)
|
|
||||||
{
|
|
||||||
auto stringDataLen = reader->ReadUInt32();
|
|
||||||
auto stringData = reader->ReadString(stringDataLen);
|
|
||||||
auto intData = reader->ReadInt32();
|
|
||||||
tokenVector->emplace_back(stringData->Data(), intData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenVector;
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime Utils::GetUniversalSystemTime()
|
DateTime Utils::GetUniversalSystemTime()
|
||||||
{
|
{
|
||||||
SYSTEMTIME sysTime = {};
|
SYSTEMTIME sysTime = {};
|
||||||
|
@ -196,3 +127,133 @@ task<String ^> Utils::ReadFileFromFolder(IStorageFolder ^ folder, String ^ fileN
|
||||||
String ^ contents = co_await FileIO::ReadTextAsync(file);
|
String ^ contents = co_await FileIO::ReadTextAsync(file);
|
||||||
co_return contents;
|
co_return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Utils::AreColorsEqual(const Color& color1, const Color& color2)
|
||||||
|
{
|
||||||
|
return ((color1.A == color2.A)
|
||||||
|
&& (color1.R == color2.R)
|
||||||
|
&& (color1.G == color2.G)
|
||||||
|
&& (color1.B == color2.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
String^ Utils::Trim(String^ value)
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring trimmed = value->Data();
|
||||||
|
Trim(trimmed);
|
||||||
|
return ref new String(trimmed.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::Trim(wstring& value)
|
||||||
|
{
|
||||||
|
TrimFront(value);
|
||||||
|
TrimBack(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::TrimFront(wstring& value)
|
||||||
|
{
|
||||||
|
value.erase(value.begin(), find_if(value.cbegin(), value.cend(), [](int ch){
|
||||||
|
return !isspace(ch);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::TrimBack(wstring& value)
|
||||||
|
{
|
||||||
|
value.erase(find_if(value.crbegin(), value.crend(), [](int ch) {
|
||||||
|
return !isspace(ch);
|
||||||
|
}).base(), value.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
String^ Utils::EscapeHtmlSpecialCharacters(String^ originalString, shared_ptr<vector<wchar_t>> specialCharacters)
|
||||||
|
{
|
||||||
|
// Construct a default special characters if not provided.
|
||||||
|
if (specialCharacters == nullptr)
|
||||||
|
{
|
||||||
|
specialCharacters = make_shared<vector<wchar_t>>();
|
||||||
|
specialCharacters->push_back(L'&');
|
||||||
|
specialCharacters->push_back(L'\"');
|
||||||
|
specialCharacters->push_back(L'\'');
|
||||||
|
specialCharacters->push_back(L'<');
|
||||||
|
specialCharacters->push_back(L'>');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool replaceCharacters = false;
|
||||||
|
const wchar_t* pCh;
|
||||||
|
String^ replacementString = nullptr;
|
||||||
|
|
||||||
|
// First step is scanning the string for special characters.
|
||||||
|
// If there isn't any special character, we simply return the original string
|
||||||
|
for (pCh = originalString->Data(); *pCh; pCh++)
|
||||||
|
{
|
||||||
|
if (std::find(specialCharacters->begin(), specialCharacters->end(), *pCh) != specialCharacters->end())
|
||||||
|
{
|
||||||
|
replaceCharacters = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceCharacters)
|
||||||
|
{
|
||||||
|
// If we indeed find a special character, we step back one character (the special
|
||||||
|
// character), and we create a new string where we replace those characters one by one
|
||||||
|
pCh--;
|
||||||
|
wstringstream buffer;
|
||||||
|
buffer << wstring(originalString->Data(), pCh);
|
||||||
|
|
||||||
|
for (; *pCh; pCh++)
|
||||||
|
{
|
||||||
|
switch (*pCh)
|
||||||
|
{
|
||||||
|
case L'&':
|
||||||
|
buffer << L"&";
|
||||||
|
break;
|
||||||
|
case L'\"':
|
||||||
|
buffer << L""";
|
||||||
|
break;
|
||||||
|
case L'\'':
|
||||||
|
buffer << L"'";
|
||||||
|
break;
|
||||||
|
case L'<':
|
||||||
|
buffer << L"<";
|
||||||
|
break;
|
||||||
|
case L'>':
|
||||||
|
buffer << L">";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buffer << *pCh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replacementString = ref new String(buffer.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return replaceCharacters ? replacementString : originalString;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Color& color1, const Color& color2)
|
||||||
|
{
|
||||||
|
return equal_to<Color>()(color1, color2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Color& color1, const Color& color2)
|
||||||
|
{
|
||||||
|
return !(color1 == color2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method calculates the luminance ratio between White and the given background color.
|
||||||
|
// The luminance is calculate using the RGB values and does not use the A value.
|
||||||
|
// White or Black is returned
|
||||||
|
SolidColorBrush ^ Utils::GetContrastColor(Color backgroundColor)
|
||||||
|
{
|
||||||
|
auto luminance = 0.2126 * backgroundColor.R + 0.7152 * backgroundColor.G + 0.0722 * backgroundColor.B;
|
||||||
|
|
||||||
|
if ((255 + 0.05) / (luminance + 0.05) >= 2.5)
|
||||||
|
{
|
||||||
|
return static_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"WhiteBrush"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"BlackBrush"));
|
||||||
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue