Hello C# - Migrating the codebase from C++/CX to C# (Phase 1) (#1598)

* Hello C# - Going to an official feature branch (#1544)

* change CalcViewModel into a WindowsRuntimeComponent project (#5)

* change CalcViewModel into a WindowsRuntimeComponent project

* remove the old UI codebase (#6)

* initially migrated C# codebase by tian (#7)

* initial migrated C# codebase by tian

* format the codebase

* resolve comments

* undo: modifications on UI test project

* Remove the blocks that have more than 1 empty line.

* Register DP using keyword 'nameof'

* C# Migration: Initially migrated C# codebase by Han (#8)

* C# Migration: Initially migrated C# codebase by Han

* Resolved comments and misssing asset

* Added three files to Calculator project

* Added TODO comment and updated Object

* NavCategory: temporary resolution of the hang issue (#9)

* Updated CalcViewModel and missing files (#10)

* Updated CalcViewModel and WinMeta

* Added Calculator.rc

* Resolved comment for InitializeLocalizationSettings

* add: views/unitconverter.xaml (#11)

* add: views/unitconverter.xaml

* format the code

* remove the extra empty line

* add an empty line

* check null before invoking event handlers (#12)

* fix problems of the migration of OBSERVABLE_PROPERTY_RW (#13)

* fixes crash in MathRichEditBox.ctor() (#14)

* fixes crash in MathRichEditBox.ctor()

* typo

* Update azure-pipelines.ci.yaml for Azure Pipelines

* Added a link copy of CalcViewModel to temporarily pass Unit Tests (#16)

* Updated CalcViewModelCopyForUT configuration (#17)

* changes output path of the UI project to align with other projects (#15)

* fixes EETypeLoadException issue: export class DelegateCommand (#18)

* fixes EETypeLoadException issue: export class DelegateCommand

* weak-reference in C++/CX

* WeakRef in C# codebase

* UTF-8-BOM

* spaces in macro

* resolve some comments from the offline review

* format

* rename file

* fixes the memory list issue (#20)

* fixes a wrongly migrated property

* UTF-8-BOM

* fixes up the crash of type casting (#21)

* Update localized strings 2021-01-04 (#1458) (#23)

(cherry picked from commit cdcb95656d)

Co-authored-by: Matt Cooley <macool@microsoft.com>

* Fixup tests (#1429) (#24)

- Removed unneeded "ToString" calls
- Fixed typos
- Renamed "fEButtonState" to "FEButtonState"

(cherry picked from commit 66ad328d00)

Co-authored-by: N <71219152+PokeCodec@users.noreply.github.com>

* Update graph internal engine verseion (#1466) (#25)

(cherry picked from commit 0048dcb500)

Co-authored-by: Quentin Al-Timimi <27322516+quentin987@users.noreply.github.com>

* Turn off DFS file shares in internal build system (#1470) (#26)

(cherry picked from commit 885fa23a89)

Co-authored-by: Matt Cooley <macool@microsoft.com>

* Improve clarity of math expressions in history for Standard Calculator (feature #138) (#1453) (#27)

* Implemented feature & added unit tests

* Fixed more unit/ui tests

* Refactored tests

* Update HistoryTests.cpp

* Update HistoryTests.cpp

* Update HistoryTests.cpp

* Update HistoryTests.cpp

* Update HistoryTests.cpp

* Update HistoryTests.cpp

* Update HistoryTests.cpp

* Update HistoryTests.cpp

(cherry picked from commit 565e3e2714)

Co-authored-by: Wei (Waley) Zhang <waley.zhang@microsoft.com>

* Adds unit-test cases for NarratorAnnouncement after fixing issue #1386 (#1469) (#28)

* fix bug: No confirmation is announced by the narrator after activating 'Remove equation' button #1386

* Unit Test: Add NarratorAnnouncementUnitTests

Co-authored-by: tain <tankle_@hotmail.com>
(cherry picked from commit 9d8e2ad18c)

Co-authored-by: Tian L <60599517+MSFT-Tilia@users.noreply.github.com>

* Move localization pipeline sync schedule to the YAML file (#1478) (#30)

(cherry picked from commit 007eccd940)

Co-authored-by: Matt Cooley <macool@microsoft.com>

* remove the strong reference carried from delegate (#32)

* Remove the finalizer of ControlSizeTrigger (#31)

* Normalize the namespace of CalcViewModel (#33)

* ViewMode: arrange namespaces

* UI build pass

* run release

* UT build pass

* pass build

* resolve comment: make the diff results cleaner

* resolve comment: make the diff results cleaner (2)

* resolve comment: make the diff results cleaner (3)

* resolve comment: move impl into a namespace

* update: spaces

* update: CalculatorButtonUser.h

* UTF-8 to UTF-8-BOM

* remove ViewState.h/.cpp from CalcViewModel path

* revert changes for NavCategory.cpp

* remove extra space

* remove UCM

* remove BOM

* Fixed a graphing calculator "permissions" bug caused by PR #1426 (#1471) (#34)

- The PR #1426 can cause a crash when no users are returned via `User::FindAllAsync(UserType::LocalUser)` when subsequently trying to access the first user. The existing code also does not guarantee that the returned user is the currently active user.
- This fix retrieves the user that opened the app and passes this user into a function to check if this user has the proper permissions to access the graphing mode. This makes sense since the active user is indistinguishable (at least from the app's perspective) to the user who opened the app. This user's permissions are then propagated downwards to properly set up the navigation menu of the app.
- Implementation detail worth pointing out: `s_categoryManifest` is what is used to populate the navigation menu of the app, but this variable is static by design, so a separate function was written to override the appropriate `isEnabled` value in `s_categoryManifest`. This function is called by `onLaunched`.

- Manual testing

Co-authored-by: Wei (Waley) Zhang <waley.zhang@microsoft.com>

* fixes up a bug (#35)

* fix csproj (#37)

Co-authored-by: hanzhang54 <zhangh@microsoft.com>
Co-authored-by: Matt Cooley <macool@microsoft.com>
Co-authored-by: N <71219152+PokeCodec@users.noreply.github.com>
Co-authored-by: Quentin Al-Timimi <27322516+quentin987@users.noreply.github.com>
Co-authored-by: Wei (Waley) Zhang <waley.zhang@microsoft.com>
Co-authored-by: Tian L <60599517+MSFT-Tilia@users.noreply.github.com>

* **BYPASS_SECRET_SCANNING** (#1546)

* Fixes a bug about the UI of expression tokens (#1547)

* fix

* [FeatureBranch] Fixes x86/ARM/ARM64 builds for the CI-Pipeline (#1550)

* **BYPASS_SECRET_SCANNING**

* fix

* fixes x86/ARM/ARM64 builds for CI-Pipeline

* Add headers missing for compilation with GCC (#1468) (#1551)

Things that required such update included:
* `wstringstream`
* `setprecision`
* `SCODE_CODE`, `E_BOUNDS`
* Various SAL macros

Co-authored-by: Michał Janiszewski <janisozaur@users.noreply.github.com>

* Update nuget.config file (#1486) (#1552)

Co-authored-by: Matt Cooley <macool@microsoft.com>

* Fixes up some simple miscellaneous TODO items (#1556)

* #DEBUG is a known C# preprocessor directive

* So far, we haven't observed the problem described in the comment from C# async

* fixes misc TODO items

* resolve some warnings (#1564)

* Add internal CI pipeline (#1553) (#1565)

* Add CI-internal pipeline

* No ARM64, to match release

Co-authored-by: Matt Cooley <macool@microsoft.com>

* Temporarily disable PGO NuGet package (#1510) (#1566)

Co-authored-by: Matt Cooley <macool@microsoft.com>

* [C# Calc]Removes WinMeta.cs (#1567)

* remove WinMeta.cs

* undo a trivial change

* UTF-8 BOM

* [C# Calc] Reverts some changes for Currency constants (#1570)

* Update2108release - experimental (#1572)

* adjusts Calculator.csproj (#1571)

* fixes BinSkim problems (#1573)

* fixes an issue around line style (#1575)

* fixes the missed NULLs (#1576) (#1578)

* Fix the Missing Part in Unit Converter Constructor (#1579)

* fixes: calculator doesn't remember its previous mode (#1580)

* Fixes: GraphingNumber doesn't work correctly (#1585)

* fixes: GraphingNumber doesn't work correctly

* Avoid crashing

* fixes binding (#1586)

* resolve TODO items (#1589)

* Improving keyboard support in VariableValueSlider (#1559) (#1595)

Co-authored-by: Dave Grochocki <grochocki@users.noreply.github.com>

* [C# Calc] Fixes: Keep the value away from getting rounded in Graphing Mode (#1596)

* keep the value away from getting rounded

* set the display precision to 6 to align with C++ impl

* fixes the button-light-up time (#1597)

* fixes up merging flaws

* Update2108release

* fixes (#1599)

* keep master for ci pipeline

* remove the Resources filter from CalcViewModel project

* removes `that` since `this` can be captured automatically

* AppxBundlePlatforms

* StampAssemblyInfo

* removes PreferredToolArchitecture

* Change the arg AppVersion into Version

* Change the arg AppVersion into Version

* from Calculator.rc to AssemblyInfo.cs

* Adds assembly-info

Co-authored-by: hanzhang54 <zhangh@microsoft.com>
Co-authored-by: Matt Cooley <macool@microsoft.com>
Co-authored-by: N <71219152+PokeCodec@users.noreply.github.com>
Co-authored-by: Quentin Al-Timimi <27322516+quentin987@users.noreply.github.com>
Co-authored-by: Wei (Waley) Zhang <waley.zhang@microsoft.com>
Co-authored-by: Tian L <60599517+MSFT-Tilia@users.noreply.github.com>
Co-authored-by: Michał Janiszewski <janisozaur@users.noreply.github.com>
Co-authored-by: Dave Grochocki <grochocki@users.noreply.github.com>
This commit is contained in:
Tian L
2021-07-15 17:12:38 +08:00
committed by GitHub
parent 233339d289
commit fdae1000fc
300 changed files with 14563 additions and 16717 deletions

View File

@@ -82,11 +82,13 @@
FontSize="{ThemeResource BodyFontSize}"
TextWrapping="Wrap">
<Paragraph>
<Run x:Name="ContributeRunBeforeLink"/><Hyperlink NavigateUri="https://go.microsoft.com/fwlink/?linkid=2099939"
<Run x:Name="ContributeRunBeforeLink"/>
<Hyperlink NavigateUri="https://go.microsoft.com/fwlink/?linkid=2099939"
TextDecorations="None"
ToolTipService.ToolTip="https://go.microsoft.com/fwlink/?linkid=2099939">
<Run x:Name="ContributeRunLink"/>
</Hyperlink><Run x:Name="ContributeRunAfterLink"/>
</Hyperlink>
<Run x:Name="ContributeRunAfterLink"/>
</Paragraph>
</RichTextBlock>
</Grid>

View File

@@ -1,92 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "AboutFlyout.xaml.h"
#include "CalcViewModel/Common/AppResourceProvider.h"
#include "CalcViewModel/Common/LocalizationService.h"
#include "CalcViewModel/Common/LocalizationStringUtil.h"
#include "CalcViewModel/Common/TraceLogger.h"
using namespace std;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace Platform;
using namespace Windows::ApplicationModel;
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
#ifndef BUILD_YEAR
#define BUILD_YEAR 2021
#endif
AboutFlyout::AboutFlyout()
{
auto locService = LocalizationService::GetInstance();
auto resourceLoader = AppResourceProvider::GetInstance();
InitializeComponent();
Language = locService->GetLanguage();
this->SetVersionString();
Header->Text = resourceLoader->GetResourceString("AboutButton/Content");
auto copyrightText =
LocalizationStringUtil::GetLocalizedString(resourceLoader->GetResourceString("AboutControlCopyright"), StringReference(to_wstring(BUILD_YEAR).c_str()));
AboutControlCopyrightRun->Text = copyrightText;
InitializeContributeTextBlock();
}
void AboutFlyout::FeedbackButton_Click(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
{
PackageVersion version = Package::Current->Id->Version;
String ^ versionNumber = ref new String(L"Version ");
versionNumber = versionNumber + version.Major + "." + version.Minor + "." + version.Build + "." + version.Revision;
Launcher::LaunchUriAsync(ref new Uri("windows-feedback:?contextid=130&metadata=%7B%22Metadata%22:[%7B%22AppBuild%22:%22" + versionNumber + "%22%7D]%7D"));
}
void AboutFlyout::SetVersionString()
{
PackageVersion version = Package::Current->Id->Version;
String ^ appName = AppResourceProvider::GetInstance()->GetResourceString(L"AppName");
AboutFlyoutVersion->Text = appName + L" " + version.Major + L"." + version.Minor + L"." + version.Build + L"." + version.Revision;
}
void AboutFlyout::SetDefaultFocus()
{
AboutFlyoutEULA->Focus(::FocusState::Programmatic);
}
void AboutFlyout::InitializeContributeTextBlock()
{
auto resProvider = AppResourceProvider::GetInstance();
std::wstring contributeHyperlinkText = resProvider->GetResourceString(L"AboutFlyoutContribute")->Data();
// The resource string has the 'GitHub' hyperlink wrapped with '%HL%'.
// Break the string and assign pieces appropriately.
static const std::wstring delimiter{ L"%HL%" };
static const size_t delimiterLength{ delimiter.length() };
// Find the delimiters.
size_t firstSplitPosition = contributeHyperlinkText.find(delimiter, 0);
assert(firstSplitPosition != std::wstring::npos);
size_t secondSplitPosition = contributeHyperlinkText.find(delimiter, firstSplitPosition + 1);
assert(secondSplitPosition != std::wstring::npos);
size_t hyperlinkTextLength = secondSplitPosition - (firstSplitPosition + delimiterLength);
// Assign pieces.
auto contributeTextBeforeHyperlink = ref new String(contributeHyperlinkText.substr(0, firstSplitPosition).c_str());
auto contributeTextLink = ref new String(contributeHyperlinkText.substr(firstSplitPosition + delimiterLength, hyperlinkTextLength).c_str());
auto contributeTextAfterHyperlink = ref new String(contributeHyperlinkText.substr(secondSplitPosition + delimiterLength).c_str());
ContributeRunBeforeLink->Text = contributeTextBeforeHyperlink;
ContributeRunLink->Text = contributeTextLink;
ContributeRunAfterLink->Text = contributeTextAfterHyperlink;
}

View File

@@ -0,0 +1,86 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
using System;
using System.Diagnostics;
using Windows.ApplicationModel;
using Windows.System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
public sealed partial class AboutFlyout
{
// CSHARP_MIGRATION: TODO:
// BUILD_YEAR was a C++/CX macro and may update the value from the pipeline
private const string BUILD_YEAR = "2021";
public AboutFlyout()
{
var locService = LocalizationService.GetInstance();
var resourceLoader = AppResourceProvider.GetInstance();
InitializeComponent();
Language = locService.GetLanguage();
SetVersionString();
Header.Text = resourceLoader.GetResourceString("AboutButton/Content");
var copyrightText =
LocalizationStringUtil.GetLocalizedString(resourceLoader.GetResourceString("AboutControlCopyright"), BUILD_YEAR);
AboutControlCopyrightRun.Text = copyrightText;
InitializeContributeTextBlock();
}
public void SetDefaultFocus()
{
AboutFlyoutEULA.Focus(FocusState.Programmatic);
}
private void FeedbackButton_Click(object sender, RoutedEventArgs e)
{
PackageVersion version = Package.Current.Id.Version;
string versionNumber = "Version ";
versionNumber = versionNumber + version.Major + "." + version.Minor + "." + version.Build + "." + version.Revision;
_ = Launcher.LaunchUriAsync(new Uri("windows-feedback:?contextid=130&metadata=%7B%22Metadata%22:[%7B%22AppBuild%22:%22" + versionNumber + "%22%7D]%7D"));
}
private void SetVersionString()
{
PackageVersion version = Package.Current.Id.Version;
string appName = AppResourceProvider.GetInstance().GetResourceString("AppName");
AboutFlyoutVersion.Text = appName + " " + version.Major + "." + version.Minor + "." + version.Build + "." + version.Revision;
}
private void InitializeContributeTextBlock()
{
var resProvider = AppResourceProvider.GetInstance();
string contributeHyperlinkText = resProvider.GetResourceString("AboutFlyoutContribute");
// The resource string has the 'GitHub' hyperlink wrapped with '%HL%'.
// Break the string and assign pieces appropriately.
string delimiter = "%HL%";
int delimiterLength = delimiter.Length;
// Find the delimiters.
int firstSplitPosition = contributeHyperlinkText.IndexOf(delimiter, 0);
Debug.Assert(firstSplitPosition != -1);
int secondSplitPosition = contributeHyperlinkText.IndexOf(delimiter, firstSplitPosition + 1);
Debug.Assert(secondSplitPosition != -1);
int hyperlinkTextLength = secondSplitPosition - (firstSplitPosition + delimiterLength);
// Assign pieces.
var contributeTextBeforeHyperlink = contributeHyperlinkText.Substring(0, firstSplitPosition);
var contributeTextLink = contributeHyperlinkText.Substring(firstSplitPosition + delimiterLength, hyperlinkTextLength);
var contributeTextAfterHyperlink = contributeHyperlinkText.Substring(secondSplitPosition + delimiterLength);
ContributeRunBeforeLink.Text = contributeTextBeforeHyperlink;
ContributeRunLink.Text = contributeTextLink;
ContributeRunAfterLink.Text = contributeTextAfterHyperlink;
}
}
}

View File

@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "AboutFlyout.g.h"
namespace CalculatorApp
{
public
ref class AboutFlyout sealed
{
public:
AboutFlyout();
void SetDefaultFocus();
private:
void FeedbackButton_Click(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void SetVersionString();
void InitializeContributeTextBlock();
};
} /* namespace CalculatorApp */

View File

@@ -1,439 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// App.xaml.cpp
// Implementation of the App class.
//
#include "pch.h"
#include "App.xaml.h"
#include "CalcViewModel/Common/TraceLogger.h"
#include "CalcViewModel/Common/Automation/NarratorNotifier.h"
#include "CalcViewModel/Common/AppResourceProvider.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
#include "Views/MainPage.xaml.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Common::Automation;
using namespace Concurrency;
using namespace Microsoft::WRL;
using namespace Platform;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Storage;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::Popups;
using namespace Windows::UI::StartScreen;
using namespace Windows::UI::ViewManagement;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Media::Animation;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::ApplicationModel::Activation;
namespace CalculatorApp
{
namespace ApplicationResourceKeys
{
StringReference AppMinWindowHeight(L"AppMinWindowHeight");
StringReference AppMinWindowWidth(L"AppMinWindowWidth");
}
}
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
App::App()
{
InitializeComponent();
m_preLaunched = false;
RegisterDependencyProperties();
// TODO: MSFT 14645325: Set this directly from XAML.
// Currently this is bugged so the property is only respected from code-behind.
this->HighContrastAdjustment = ApplicationHighContrastAdjustment::None;
this->Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
#if _DEBUG
this->DebugSettings->IsBindingTracingEnabled = true;
this->DebugSettings->BindingFailed += ref new BindingFailedEventHandler([](_In_ Object ^ /*sender*/, _In_ BindingFailedEventArgs ^ e) {
if (IsDebuggerPresent())
{
::Platform::String ^ errorMessage = e->Message;
__debugbreak();
}
});
#endif
}
void App::AddWindowToMap(_In_ WindowFrameService ^ frameService)
{
reader_writer_lock::scoped_lock lock(m_windowsMapLock);
m_secondaryWindows[frameService->GetViewId()] = frameService;
TraceLogger::GetInstance()->UpdateWindowCount(m_secondaryWindows.size());
}
WindowFrameService ^ App::GetWindowFromMap(int viewId)
{
reader_writer_lock::scoped_lock_read lock(m_windowsMapLock);
auto windowMapEntry = m_secondaryWindows.find(viewId);
if (windowMapEntry != m_secondaryWindows.end())
{
return windowMapEntry->second;
}
return nullptr;
}
void App::RemoveWindowFromMap(int viewId)
{
reader_writer_lock::scoped_lock lock(m_windowsMapLock);
auto iter = m_secondaryWindows.find(viewId);
assert(iter != m_secondaryWindows.end() && "Window does not exist in the list");
m_secondaryWindows.erase(viewId);
}
void App::RemoveWindow(_In_ WindowFrameService ^ frameService)
{
// Shell does not allow killing the main window.
if (m_mainViewId != frameService->GetViewId())
{
HandleViewReleaseAndRemoveWindowFromMap(frameService);
}
}
task<void> App::HandleViewReleaseAndRemoveWindowFromMap(_In_ WindowFrameService ^ frameService)
{
WeakReference weak(this);
// Unregister the event handler of the Main Page
auto frame = safe_cast<Frame ^>(Window::Current->Content);
auto mainPage = safe_cast<MainPage ^>(frame->Content);
mainPage->UnregisterEventHandlers();
return frameService->HandleViewRelease().then(
[weak, frameService]() {
auto that = weak.Resolve<App>();
that->RemoveWindowFromMap(frameService->GetViewId());
},
task_continuation_context::use_arbitrary());
}
#pragma optimize("", off) // Turn off optimizations to work around coroutine optimization bug
task<void> App::SetupJumpList()
{
try
{
auto calculatorOptions = NavCategoryGroup::CreateCalculatorCategory();
auto jumpList = co_await JumpList::LoadCurrentAsync();
jumpList->SystemGroupKind = JumpListSystemGroupKind::None;
jumpList->Items->Clear();
for (NavCategory ^ option : calculatorOptions->Categories)
{
if (!option->IsEnabled)
{
continue;
}
ViewMode mode = option->Mode;
auto item = JumpListItem::CreateWithArguments(((int)mode).ToString(), L"ms-resource:///Resources/" + NavCategory::GetNameResourceKey(mode));
item->Description = L"ms-resource:///Resources/" + NavCategory::GetNameResourceKey(mode);
item->Logo = ref new Uri("ms-appx:///Assets/" + mode.ToString() + ".png");
jumpList->Items->Append(item);
}
co_await jumpList->SaveAsync();
}
catch (...)
{
}
};
#pragma optimize("", on)
void App::RemoveSecondaryWindow(_In_ WindowFrameService ^ frameService)
{
// Shell does not allow killing the main window.
if (m_mainViewId != frameService->GetViewId())
{
RemoveWindowFromMap(frameService->GetViewId());
}
}
Frame ^ App::CreateFrame()
{
auto frame = ref new Frame();
frame->FlowDirection = LocalizationService::GetInstance()->GetFlowDirection();
return frame;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
void App::OnLaunched(LaunchActivatedEventArgs ^ args)
{
if (args->PrelaunchActivated)
{
// If the app got pre-launch activated, then save that state in a flag
m_preLaunched = true;
}
NavCategory::InitializeCategoryManifest(args->User);
OnAppLaunch(args, args->Arguments);
}
void App::OnAppLaunch(IActivatedEventArgs ^ args, String ^ argument)
{
// Uncomment the following lines to display frame-rate and per-frame CPU usage info.
//#if _DEBUG
// if (IsDebuggerPresent())
// {
// DebugSettings->EnableFrameRateCounter = true;
// }
//#endif
args->SplashScreen->Dismissed += ref new TypedEventHandler<SplashScreen ^, Object ^>(this, &App::DismissedEventHandler);
auto rootFrame = dynamic_cast<Frame ^>(Window::Current->Content);
WeakReference weak(this);
float minWindowWidth = static_cast<float>(static_cast<double>(this->Resources->Lookup(ApplicationResourceKeys::AppMinWindowWidth)));
float minWindowHeight = static_cast<float>(static_cast<double>(this->Resources->Lookup(ApplicationResourceKeys::AppMinWindowHeight)));
Size minWindowSize = SizeHelper::FromDimensions(minWindowWidth, minWindowHeight);
ApplicationView ^ appView = ApplicationView::GetForCurrentView();
ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings;
// For very first launch, set the size of the calc as size of the default standard mode
if (!localSettings->Values->HasKey(L"VeryFirstLaunch"))
{
localSettings->Values->Insert(ref new String(L"VeryFirstLaunch"), false);
appView->SetPreferredMinSize(minWindowSize);
appView->TryResizeView(minWindowSize);
}
else
{
appView->PreferredLaunchWindowingMode = ApplicationViewWindowingMode::Auto;
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
if (!Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) // PC Family
{
// Disable the system view activation policy during the first launch of the app
// only for PC family devices and not for phone family devices
try
{
ApplicationViewSwitcher::DisableSystemViewActivationPolicy();
}
catch (Exception ^ e)
{
// Log that DisableSystemViewActionPolicy didn't work
}
}
// Create a Frame to act as the navigation context
rootFrame = App::CreateFrame();
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame->Navigate(MainPage::typeid, argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw std::bad_exception();
}
SetMinWindowSizeAndActivate(rootFrame, minWindowSize);
m_mainViewId = ApplicationView::GetForCurrentView()->Id;
AddWindowToMap(WindowFrameService::CreateNewWindowFrameService(rootFrame, false, weak));
}
else
{
// For first launch, LaunchStart is logged in constructor, this is for subsequent launches.
// !Phone check is required because even in continuum mode user interaction mode is Mouse not Touch
if ((UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Mouse)
&& (!Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")))
{
// If the pre-launch hasn't happened then allow for the new window/view creation
if (!m_preLaunched)
{
auto newCoreAppView = CoreApplication::CreateNewView();
newCoreAppView->Dispatcher->RunAsync(
CoreDispatcherPriority::Normal, ref new DispatchedHandler([args, argument, minWindowSize, weak]() {
auto that = weak.Resolve<App>();
if (that != nullptr)
{
auto rootFrame = App::CreateFrame();
SetMinWindowSizeAndActivate(rootFrame, minWindowSize);
if (!rootFrame->Navigate(MainPage::typeid, argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw std::bad_exception();
}
auto frameService = WindowFrameService::CreateNewWindowFrameService(rootFrame, true, weak);
that->AddWindowToMap(frameService);
auto dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
auto safeFrameServiceCreation = std::make_shared<SafeFrameWindowCreation>(frameService, that);
int newWindowId = ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread());
ActivationViewSwitcher ^ activationViewSwitcher;
auto activateEventArgs = dynamic_cast<IViewSwitcherProvider ^>(args);
if (activateEventArgs != nullptr)
{
activationViewSwitcher = activateEventArgs->ViewSwitcher;
}
if (activationViewSwitcher != nullptr)
{
activationViewSwitcher->ShowAsStandaloneAsync(newWindowId, ViewSizePreference::Default);
safeFrameServiceCreation->SetOperationSuccess(true);
}
else
{
auto activatedEventArgs = dynamic_cast<IApplicationViewActivatedEventArgs ^>(args);
if ((activatedEventArgs != nullptr) && (activatedEventArgs->CurrentlyShownApplicationViewId != 0))
{
create_task(ApplicationViewSwitcher::TryShowAsStandaloneAsync(
frameService->GetViewId(),
ViewSizePreference::Default,
activatedEventArgs->CurrentlyShownApplicationViewId,
ViewSizePreference::Default))
.then(
[safeFrameServiceCreation](bool viewShown) {
// SafeFrameServiceCreation is used to automatically remove the frame
// from the list of frames if something goes bad.
safeFrameServiceCreation->SetOperationSuccess(viewShown);
},
task_continuation_context::use_current());
}
}
}
}));
}
else
{
ActivationViewSwitcher ^ activationViewSwitcher;
auto activateEventArgs = dynamic_cast<IViewSwitcherProvider ^>(args);
if (activateEventArgs != nullptr)
{
activationViewSwitcher = activateEventArgs->ViewSwitcher;
}
if (activationViewSwitcher != nullptr)
{
activationViewSwitcher->ShowAsStandaloneAsync(
ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()), ViewSizePreference::Default);
}
else
{
TraceLogger::GetInstance()->LogError(ViewMode::None, L"App::OnAppLaunch", L"Null_ActivationViewSwitcher");
}
}
// Set the preLaunched flag to false
m_preLaunched = false;
}
else // for touch devices
{
if (rootFrame->Content == nullptr)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame->Navigate(MainPage::typeid, argument))
{
// We couldn't navigate to the main page,
// kill the app so we have a good stack to debug
throw std::bad_exception();
}
}
if (ApplicationView::GetForCurrentView()->ViewMode != ApplicationViewMode::CompactOverlay)
{
if (!Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
{
// for tablet mode: since system view activation policy is disabled so do ShowAsStandaloneAsync if activationViewSwitcher exists in
// activationArgs
ActivationViewSwitcher ^ activationViewSwitcher;
auto activateEventArgs = dynamic_cast<IViewSwitcherProvider ^>(args);
if (activateEventArgs != nullptr)
{
activationViewSwitcher = activateEventArgs->ViewSwitcher;
}
if (activationViewSwitcher != nullptr)
{
auto viewId = safe_cast<IApplicationViewActivatedEventArgs ^>(args)->CurrentlyShownApplicationViewId;
if (viewId != 0)
{
activationViewSwitcher->ShowAsStandaloneAsync(viewId);
}
}
}
// Ensure the current window is active
Window::Current->Activate();
}
}
}
}
void App::SetMinWindowSizeAndActivate(Frame ^ rootFrame, Size minWindowSize)
{
// SetPreferredMinSize should always be called before Window::Activate
ApplicationView ^ appView = ApplicationView::GetForCurrentView();
appView->SetPreferredMinSize(minWindowSize);
// Place the frame in the current Window
Window::Current->Content = rootFrame;
Window::Current->Activate();
}
void App::RegisterDependencyProperties()
{
NarratorNotifier::RegisterDependencyProperties();
}
void App::OnActivated(IActivatedEventArgs ^ args)
{
if (args->Kind == ActivationKind::Protocol)
{
// We currently don't pass the uri as an argument,
// and handle any protocol launch as a normal app launch.
OnAppLaunch(args, nullptr);
}
}
void CalculatorApp::App::OnSuspending(Object ^ sender, SuspendingEventArgs ^ args)
{
TraceLogger::GetInstance()->LogButtonUsage();
}
void App::DismissedEventHandler(SplashScreen ^ sender, Object ^ e)
{
SetupJumpList();
}

504
src/Calculator/App.xaml.cs Normal file
View File

@@ -0,0 +1,504 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// App.xaml.h
// Declaration of the App class.
//
using CalculatorApp.ViewModel.Common;
using CalculatorApp.ViewModel.Common.Automation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.StartScreen;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace CalculatorApp
{
namespace ApplicationResourceKeys
{
static public partial class Globals
{
public static readonly string AppMinWindowHeight = "AppMinWindowHeight";
public static readonly string AppMinWindowWidth = "AppMinWindowWidth";
}
}
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
InitializeComponent();
m_preLaunched = false;
RegisterDependencyProperties();
// TODO: MSFT 14645325: Set this directly from XAML.
// Currently this is bugged so the property is only respected from code-behind.
HighContrastAdjustment = ApplicationHighContrastAdjustment.None;
Suspending += OnSuspending;
#if DEBUG
DebugSettings.IsBindingTracingEnabled = true;
DebugSettings.BindingFailed += (sender, args) =>
{
if (Debugger.IsAttached)
{
string errorMessage = args.Message;
Debugger.Break();
}
};
#endif
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
if (args.PrelaunchActivated)
{
// If the app got pre-launch activated, then save that state in a flag
m_preLaunched = true;
}
NavCategory.InitializeCategoryManifest(args.User);
OnAppLaunch(args, args.Arguments);
}
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.Protocol)
{
// We currently don't pass the uri as an argument,
// and handle any protocol launch as a normal app launch.
OnAppLaunch(args, null);
}
}
internal void RemoveWindow(WindowFrameService frameService)
{
// Shell does not allow killing the main window.
if (m_mainViewId != frameService.GetViewId())
{
_ = HandleViewReleaseAndRemoveWindowFromMap(frameService);
}
}
internal void RemoveSecondaryWindow(WindowFrameService frameService)
{
// Shell does not allow killing the main window.
if (m_mainViewId != frameService.GetViewId())
{
RemoveWindowFromMap(frameService.GetViewId());
}
}
private static Frame CreateFrame()
{
var frame = new Frame();
frame.FlowDirection = LocalizationService.GetInstance().GetFlowDirection();
return frame;
}
private static void SetMinWindowSizeAndActivate(Frame rootFrame, Size minWindowSize)
{
// SetPreferredMinSize should always be called before Window.Activate
ApplicationView appView = ApplicationView.GetForCurrentView();
appView.SetPreferredMinSize(minWindowSize);
// Place the frame in the current Window
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
private void OnAppLaunch(IActivatedEventArgs args, string argument)
{
// Uncomment the following lines to display frame-rate and per-frame CPU usage info.
//#if _DEBUG
// if (IsDebuggerPresent())
// {
// DebugSettings->EnableFrameRateCounter = true;
// }
//#endif
args.SplashScreen.Dismissed += DismissedEventHandler;
var rootFrame = (Window.Current.Content as Frame);
WeakReference weak = new WeakReference(this);
float minWindowWidth = (float)((double)Resources[ApplicationResourceKeys.Globals.AppMinWindowWidth]);
float minWindowHeight = (float)((double)Resources[ApplicationResourceKeys.Globals.AppMinWindowHeight]);
Size minWindowSize = SizeHelper.FromDimensions(minWindowWidth, minWindowHeight);
ApplicationView appView = ApplicationView.GetForCurrentView();
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// For very first launch, set the size of the calc as size of the default standard mode
if (!localSettings.Values.ContainsKey("VeryFirstLaunch"))
{
localSettings.Values["VeryFirstLaunch"] = false;
appView.SetPreferredMinSize(minWindowSize);
appView.TryResizeView(minWindowSize);
}
else
{
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
}
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
if (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) // PC Family
{
// Disable the system view activation policy during the first launch of the app
// only for PC family devices and not for phone family devices
try
{
ApplicationViewSwitcher.DisableSystemViewActivationPolicy();
}
catch (Exception)
{
// Log that DisableSystemViewActionPolicy didn't work
}
}
// Create a Frame to act as the navigation context
rootFrame = App.CreateFrame();
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw new SystemException();
}
SetMinWindowSizeAndActivate(rootFrame, minWindowSize);
m_mainViewId = ApplicationView.GetForCurrentView().Id;
AddWindowToMap(WindowFrameService.CreateNewWindowFrameService(rootFrame, false, weak));
}
else
{
// For first launch, LaunchStart is logged in constructor, this is for subsequent launches.
// !Phone check is required because even in continuum mode user interaction mode is Mouse not Touch
if ((UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Mouse)
&& (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")))
{
// If the pre-launch hasn't happened then allow for the new window/view creation
if (!m_preLaunched)
{
var newCoreAppView = CoreApplication.CreateNewView();
_ = newCoreAppView.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, async () =>
{
var that = weak.Target as App;
if (that != null)
{
var newRootFrame = App.CreateFrame();
SetMinWindowSizeAndActivate(newRootFrame, minWindowSize);
if (!newRootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page, kill the app so we have a good
// stack to debug
throw new SystemException();
}
var frameService = WindowFrameService.CreateNewWindowFrameService(newRootFrame, true, weak);
that.AddWindowToMap(frameService);
var dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
// CSHARP_MIGRATION_ANNOTATION:
// class SafeFrameWindowCreation is being interpreted into a IDisposable class
// in order to enhance its RAII capability that was written in C++/CX
using (var safeFrameServiceCreation = new SafeFrameWindowCreation(frameService, that))
{
int newWindowId = ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread());
ActivationViewSwitcher activationViewSwitcher = null;
var activateEventArgs = (args as IViewSwitcherProvider);
if (activateEventArgs != null)
{
activationViewSwitcher = activateEventArgs.ViewSwitcher;
}
if (activationViewSwitcher != null)
{
_ = activationViewSwitcher.ShowAsStandaloneAsync(newWindowId, ViewSizePreference.Default);
safeFrameServiceCreation.SetOperationSuccess(true);
}
else
{
var activatedEventArgs = (args as IApplicationViewActivatedEventArgs);
if ((activatedEventArgs != null) && (activatedEventArgs.CurrentlyShownApplicationViewId != 0))
{
// CSHARP_MIGRATION_ANNOTATION:
// here we don't use ContinueWith() to interpret origin code because we would like to
// pursue the design of class SafeFrameWindowCreate whichi was using RAII to ensure
// some states get handled properly when its instance is being destructed.
//
// To achieve that, SafeFrameWindowCreate has been reinterpreted using IDisposable
// pattern, which forces we use below way to keep async works being controlled within
// a same code block.
var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(
frameService.GetViewId(),
ViewSizePreference.Default,
activatedEventArgs.CurrentlyShownApplicationViewId,
ViewSizePreference.Default);
// SafeFrameServiceCreation is used to automatically remove the frame
// from the list of frames if something goes bad.
safeFrameServiceCreation.SetOperationSuccess(viewShown);
}
}
}
}
});
}
else
{
ActivationViewSwitcher activationViewSwitcher = null;
var activateEventArgs = (args as IViewSwitcherProvider);
if (activateEventArgs != null)
{
activationViewSwitcher = activateEventArgs.ViewSwitcher;
}
if (activationViewSwitcher != null)
{
_ = activationViewSwitcher.ShowAsStandaloneAsync(
ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()), ViewSizePreference.Default);
}
else
{
TraceLogger.GetInstance().LogError(ViewMode.None, "App.OnAppLaunch", "Null_ActivationViewSwitcher");
}
}
// Set the preLaunched flag to false
m_preLaunched = false;
}
else // for touch devices
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), argument))
{
// We couldn't navigate to the main page,
// kill the app so we have a good stack to debug
throw new SystemException();
}
}
if (ApplicationView.GetForCurrentView().ViewMode != ApplicationViewMode.CompactOverlay)
{
if (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
{
// for tablet mode: since system view activation policy is disabled so do ShowAsStandaloneAsync if activationViewSwitcher exists in
// activationArgs
ActivationViewSwitcher activationViewSwitcher = null;
var activateEventArgs = (args as IViewSwitcherProvider);
if (activateEventArgs != null)
{
activationViewSwitcher = activateEventArgs.ViewSwitcher;
}
if (activationViewSwitcher != null)
{
var viewId = (args as IApplicationViewActivatedEventArgs).CurrentlyShownApplicationViewId;
if (viewId != 0)
{
_ = activationViewSwitcher.ShowAsStandaloneAsync(viewId);
}
}
}
// Ensure the current window is active
Window.Current.Activate();
}
}
}
}
private void DismissedEventHandler(SplashScreen sender, object e)
{
_ = SetupJumpList();
}
private void RegisterDependencyProperties()
{
NarratorNotifier.RegisterDependencyProperties();
}
private void OnSuspending(object sender, SuspendingEventArgs args)
{
TraceLogger.GetInstance().LogButtonUsage();
}
private sealed class SafeFrameWindowCreation : IDisposable
{
public SafeFrameWindowCreation(WindowFrameService frameService, App parent)
{
m_frameService = frameService;
m_frameOpenedInWindow = false;
m_parent = parent;
}
public void SetOperationSuccess(bool success)
{
m_frameOpenedInWindow = success;
}
public void Dispose()
{
if (!m_frameOpenedInWindow)
{
// Close the window as the navigation to the window didn't succeed
// and this is not visible to the user.
m_parent.RemoveWindowFromMap(m_frameService.GetViewId());
}
GC.SuppressFinalize(this);
}
~SafeFrameWindowCreation()
{
Dispose();
}
private WindowFrameService m_frameService;
private bool m_frameOpenedInWindow;
private App m_parent;
};
private async Task SetupJumpList()
{
try
{
var calculatorOptions = NavCategoryGroup.CreateCalculatorCategory();
var jumpList = await JumpList.LoadCurrentAsync();
jumpList.SystemGroupKind = JumpListSystemGroupKind.None;
jumpList.Items.Clear();
foreach (NavCategory option in calculatorOptions.Categories)
{
if (!option.IsEnabled)
{
continue;
}
ViewMode mode = option.Mode;
var item = JumpListItem.CreateWithArguments(((int)mode).ToString(), "ms-resource:///Resources/" + NavCategory.GetNameResourceKey(mode));
item.Description = "ms-resource:///Resources/" + NavCategory.GetNameResourceKey(mode);
item.Logo = new Uri("ms-appx:///Assets/" + mode.ToString() + ".png");
jumpList.Items.Add(item);
}
await jumpList.SaveAsync();
}
catch
{
}
}
private async Task HandleViewReleaseAndRemoveWindowFromMap(WindowFrameService frameService)
{
WeakReference weak = new WeakReference(this);
// Unregister the event handler of the Main Page
var frame = (Window.Current.Content as Frame);
var mainPage = (frame.Content as MainPage);
mainPage.UnregisterEventHandlers();
await frameService.HandleViewRelease();
await Task.Run(() =>
{
var that = weak.Target as App;
that.RemoveWindowFromMap(frameService.GetViewId());
}).ConfigureAwait(false /* task_continuation_context::use_arbitrary() */);
}
private void AddWindowToMap(WindowFrameService frameService)
{
m_windowsMapLock.EnterWriteLock();
try
{
m_secondaryWindows[frameService.GetViewId()] = frameService;
TraceLogger.GetInstance().UpdateWindowCount(Convert.ToUInt64(m_secondaryWindows.Count));
}
finally
{
m_windowsMapLock.ExitWriteLock();
}
}
private WindowFrameService GetWindowFromMap(int viewId)
{
m_windowsMapLock.EnterReadLock();
try
{
if (m_secondaryWindows.TryGetValue(viewId, out var windowMapEntry))
{
return windowMapEntry;
}
else
{
return null;
}
}
finally
{
m_windowsMapLock.ExitReadLock();
}
}
private void RemoveWindowFromMap(int viewId)
{
m_windowsMapLock.EnterWriteLock();
try
{
bool removed = m_secondaryWindows.Remove(viewId);
Debug.Assert(removed != false, "Window does not exist in the list");
}
finally
{
m_windowsMapLock.ExitWriteLock();
}
}
private readonly ReaderWriterLockSlim m_windowsMapLock = new ReaderWriterLockSlim();
private Dictionary<int, WindowFrameService> m_secondaryWindows = new Dictionary<int, WindowFrameService>();
private int m_mainViewId;
private bool m_preLaunched;
}
}

View File

@@ -1,91 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// App.xaml.h
// Declaration of the App class.
//
#pragma once
#include "App.g.h"
#include "WindowFrameService.h"
namespace CalculatorApp
{
namespace ApplicationResourceKeys
{
extern Platform::StringReference AppMinWindowHeight;
extern Platform::StringReference AppMinWindowWidth;
}
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
ref class App sealed
{
public:
App();
virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^ args) override;
virtual void OnActivated(Windows::ApplicationModel::Activation::IActivatedEventArgs ^ args) override;
internal:
void RemoveWindow(_In_ WindowFrameService ^ frameService);
void RemoveSecondaryWindow(_In_ WindowFrameService ^ frameService);
private:
static Windows::UI::Xaml::Controls::Frame ^ CreateFrame();
static void SetMinWindowSizeAndActivate(Windows::UI::Xaml::Controls::Frame ^ rootFrame, Windows::Foundation::Size minWindowSize);
void OnAppLaunch(Windows::ApplicationModel::Activation::IActivatedEventArgs ^ args, Platform::String ^ argument);
void DismissedEventHandler(Windows::ApplicationModel::Activation::SplashScreen ^ sender, Platform::Object ^ e);
void RegisterDependencyProperties();
void OnSuspending(Platform::Object ^ sender, Windows::ApplicationModel::SuspendingEventArgs ^ args);
class SafeFrameWindowCreation final
{
public:
SafeFrameWindowCreation(_In_ WindowFrameService ^ frameService, App ^ parent)
: m_frameService(frameService)
, m_frameOpenedInWindow(false)
, m_parent(parent)
{
}
void SetOperationSuccess(bool success)
{
m_frameOpenedInWindow = success;
}
~SafeFrameWindowCreation()
{
if (!m_frameOpenedInWindow)
{
// Close the window as the navigation to the window didn't succeed
// and this is not visible to the user.
m_parent->RemoveWindowFromMap(m_frameService->GetViewId());
}
}
private:
WindowFrameService ^ m_frameService;
bool m_frameOpenedInWindow;
App ^ m_parent;
};
private:
concurrency::reader_writer_lock m_windowsMapLock;
std::unordered_map<int, WindowFrameService ^> m_secondaryWindows;
concurrency::task<void> SetupJumpList();
concurrency::task<void> HandleViewReleaseAndRemoveWindowFromMap(_In_ WindowFrameService ^ frameService);
void AddWindowToMap(_In_ WindowFrameService ^ frameService);
WindowFrameService ^ GetWindowFromMap(int viewId);
void RemoveWindowFromMap(int viewId);
int m_mainViewId;
bool m_preLaunched;
Windows::UI::Xaml::Controls::Primitives::Popup ^ m_aboutPopup;
};
}

View File

@@ -0,0 +1,837 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{3B773403-B0D6-4F9A-948E-512A7A5FB315}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CalculatorApp</RootNamespace>
<AssemblyName>CalculatorApp</AssemblyName>
<ApplicationType>Windows Store</ApplicationType>
<AppContainerApplication>true</AppContainerApplication>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<!-- We want to manually control the MinVersion/MaxVersionTested in the manifest so turn of the replacement. -->
<AppxOSMinVersionReplaceManifestVersion>false</AppxOSMinVersionReplaceManifestVersion>
<AppxOSMaxVersionTestedReplaceManifestVersion>false</AppxOSMaxVersionTestedReplaceManifestVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<AppxDefaultResourceQualifierUAP_Contrast>black</AppxDefaultResourceQualifierUAP_Contrast>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateKeyFile>WindowsDev_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<AppxBundle>Always</AppxBundle>
<GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>$(Platform)</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
</PropertyGroup>
<!-- This has to be exactly in this place for this to work -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\x86\Debug\Calculator\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\x86\Release\Calculator\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\ARM\Debug\Calculator\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>..\ARM\Release\Calculator\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\ARM64\Debug\Calculator\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
<OutputPath>..\ARM64\Release\Calculator\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\x64\Debug\Calculator\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>..\x64\Release\Calculator\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(IsStoreBuild)' == 'True'">
<DefineConstants>$(DefineConstants);SEND_DIAGNOSTICS;IS_STORE_BUILD</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="AboutFlyout.xaml.cs">
<DependentUpon>AboutFlyout.xaml</DependentUpon>
</Compile>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Common\AlwaysSelectedCollectionView.cs" />
<Compile Include="Common\AppLifecycleLogger.cs" />
<Compile Include="Common\KeyboardShortcuManager.cs" />
<Compile Include="Common\ValidatingConverters.cs" />
<Compile Include="Common\ViewState.cs" />
<Compile Include="Controls\CalculationResult.cs" />
<Compile Include="Controls\CalculationResultAutomationPeer.cs" />
<Compile Include="Controls\CalculatorButton.cs" />
<Compile Include="Controls\OperatorPanelButton.cs" />
<Compile Include="Controls\OperatorPanelListView.cs" />
<Compile Include="Controls\OverflowTextBlock.cs" />
<Compile Include="Controls\OverflowTextBlockAutomationPeer.cs" />
<Compile Include="Controls\EquationTextBox.cs" />
<Compile Include="Controls\FlipButtons.cs" />
<Compile Include="Controls\HorizontalNoOverflowStackPanel.cs" />
<Compile Include="Controls\MathRichEditBox.cs" />
<Compile Include="Controls\RadixButton.cs" />
<Compile Include="Controls\SupplementaryItemsControl.cs" />
<Compile Include="Converters\BooleanNegationConverter.cs" />
<Compile Include="Converters\BooleanToVisibilityConverter.cs" />
<Compile Include="Converters\ExpressionItemTemplateSelector.cs" />
<Compile Include="Converters\ItemSizeToVisibilityConverter.cs" />
<Compile Include="Converters\RadixToStringConverter.cs" />
<Compile Include="Converters\VisibilityNegationConverter.cs" />
<Compile Include="EquationStylePanelControl.xaml.cs">
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
</Compile>
<Compile Include="KeyGraphFeaturesTemplateSelector.cs" />
<Compile Include="Utils\DelegateCommandUtils.cs" />
<Compile Include="Views\Calculator.xaml.cs">
<DependentUpon>Calculator.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorProgrammerBitFlipPanel.xaml.cs">
<DependentUpon>CalculatorProgrammerBitFlipPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorProgrammerOperators.xaml.cs">
<DependentUpon>CalculatorProgrammerOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorProgrammerRadixOperators.xaml.cs">
<DependentUpon>CalculatorProgrammerRadixOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorScientificAngleButtons.xaml.cs">
<DependentUpon>CalculatorScientificAngleButtons.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorScientificOperators.xaml.cs">
<DependentUpon>CalculatorScientificOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CalculatorStandardOperators.xaml.cs">
<DependentUpon>CalculatorStandardOperators.xaml</DependentUpon>
</Compile>
<Compile Include="Views\DateCalculator.xaml.cs">
<DependentUpon>DateCalculator.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\EquationInputArea.xaml.cs">
<DependentUpon>EquationInputArea.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\GraphingCalculator.xaml.cs">
<DependentUpon>GraphingCalculator.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\GraphingNumPad.xaml.cs">
<DependentUpon>GraphingNumPad.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\GraphingSettings.xaml.cs">
<DependentUpon>GraphingSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.cs">
<DependentUpon>KeyGraphFeaturesPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\HistoryList.xaml.cs">
<DependentUpon>HistoryList.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\DispatcherTimerDelayer.cs" />
<Compile Include="Utils\VisualTree.cs" />
<Compile Include="Views\Memory.xaml.cs">
<DependentUpon>Memory.xaml</DependentUpon>
</Compile>
<Compile Include="Views\MemoryListItem.xaml.cs">
<DependentUpon>MemoryListItem.xaml</DependentUpon>
</Compile>
<Compile Include="Views\NumberPad.xaml.cs">
<DependentUpon>NumberPad.xaml</DependentUpon>
</Compile>
<Compile Include="Views\OperatorsPanel.xaml.cs">
<DependentUpon>OperatorsPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\StateTriggers\AspectRatioTrigger.cs" />
<Compile Include="Views\StateTriggers\CalculatorProgrammerDisplayPanel.xaml.cs">
<DependentUpon>CalculatorProgrammerDisplayPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\StateTriggers\ControlSizeTrigger.cs" />
<Compile Include="Views\SupplementaryResults.xaml.cs">
<DependentUpon>SupplementaryResults.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TitleBar.xaml.cs">
<DependentUpon>TitleBar.xaml</DependentUpon>
</Compile>
<Compile Include="Views\UnitConverter.xaml.cs">
<DependentUpon>UnitConverter.xaml</DependentUpon>
</Compile>
<Compile Include="WindowFrameService.cs" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup Condition="'$(IsStoreBuild)' == 'True'">
<Content Include="Assets\CalculatorAppList.scale-100.png" />
<Content Include="Assets\CalculatorAppList.scale-125.png" />
<Content Include="Assets\CalculatorAppList.scale-150.png" />
<Content Include="Assets\CalculatorAppList.scale-200.png" />
<Content Include="Assets\CalculatorAppList.scale-400.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-100.png" />
<Content Include="Assets\CalculatorLargeTile.scale-125.png" />
<Content Include="Assets\CalculatorLargeTile.scale-150.png" />
<Content Include="Assets\CalculatorLargeTile.scale-200.png" />
<Content Include="Assets\CalculatorLargeTile.scale-400.png" />
<Content Include="Assets\CalculatorMedTile.scale-100.png" />
<Content Include="Assets\CalculatorMedTile.scale-125.png" />
<Content Include="Assets\CalculatorMedTile.scale-150.png" />
<Content Include="Assets\CalculatorMedTile.scale-200.png" />
<Content Include="Assets\CalculatorMedTile.scale-400.png" />
<Content Include="Assets\CalculatorSmallTile.scale-100.png" />
<Content Include="Assets\CalculatorSmallTile.scale-125.png" />
<Content Include="Assets\CalculatorSmallTile.scale-150.png" />
<Content Include="Assets\CalculatorSmallTile.scale-200.png" />
<Content Include="Assets\CalculatorSmallTile.scale-400.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-100.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-125.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-150.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-200.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-400.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-100.png" />
<Content Include="Assets\CalculatorWideTile.scale-125.png" />
<Content Include="Assets\CalculatorWideTile.scale-150.png" />
<Content Include="Assets\CalculatorWideTile.scale-200.png" />
<Content Include="Assets\CalculatorWideTile.scale-400.png" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\CalculatorAppList.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-16_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-20_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-24_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-256_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-30_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-32_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-36_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-40_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-48_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-60_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-64_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-72_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-80_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-unplated.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_contrast-black.png" />
<Content Include="Assets\CalculatorAppList.targetsize-96_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorLargeTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorLargeTile.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorMedTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorMedTile.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorSmallTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorSmallTile.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400_altform-colorful.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorSplashScreen.scale-400_contrast-white.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorStoreLogo.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-100_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-100_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-125_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-125_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-150_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-150_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-200_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-200_contrast-white.png" />
<Content Include="Assets\CalculatorWideTile.scale-400_contrast-black.png" />
<Content Include="Assets\CalculatorWideTile.scale-400_contrast-white.png" />
<Content Include="Assets\Date.targetsize-16_contrast-black.png" />
<Content Include="Assets\Date.targetsize-16_contrast-white.png" />
<Content Include="Assets\Date.targetsize-20_contrast-black.png" />
<Content Include="Assets\Date.targetsize-20_contrast-white.png" />
<Content Include="Assets\Date.targetsize-24_contrast-black.png" />
<Content Include="Assets\Date.targetsize-24_contrast-white.png" />
<Content Include="Assets\Date.targetsize-32_contrast-black.png" />
<Content Include="Assets\Date.targetsize-32_contrast-white.png" />
<Content Include="Assets\Date.targetsize-64_contrast-black.png" />
<Content Include="Assets\Date.targetsize-64_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-16.png" />
<Content Include="Assets\Graphing.targetsize-16_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-16_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-20.png" />
<Content Include="Assets\Graphing.targetsize-20_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-20_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-24.png" />
<Content Include="Assets\Graphing.targetsize-24_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-24_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-32.png" />
<Content Include="Assets\Graphing.targetsize-32_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-32_contrast-white.png" />
<Content Include="Assets\Graphing.targetsize-64.png" />
<Content Include="Assets\Graphing.targetsize-64_contrast-black.png" />
<Content Include="Assets\Graphing.targetsize-64_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-16_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-16_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-20_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-20_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-24_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-24_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-32_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-32_contrast-white.png" />
<Content Include="Assets\Programmer.targetsize-64_contrast-black.png" />
<Content Include="Assets\Programmer.targetsize-64_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-16_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-16_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-20_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-20_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-24_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-24_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-32_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-32_contrast-white.png" />
<Content Include="Assets\Scientific.targetsize-64_contrast-black.png" />
<Content Include="Assets\Scientific.targetsize-64_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-16_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-16_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-20_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-20_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-24_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-24_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-32_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-32_contrast-white.png" />
<Content Include="Assets\Standard.targetsize-64_contrast-black.png" />
<Content Include="Assets\Standard.targetsize-64_contrast-white.png" />
<Content Include="Properties\Default.rd.xml" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Resources\af-ZA\CEngineStrings.resw" />
<PRIResource Include="Resources\af-ZA\Resources.resw" />
<PRIResource Include="Resources\am-et\CEngineStrings.resw" />
<PRIResource Include="Resources\am-et\Resources.resw" />
<PRIResource Include="Resources\ar-sa\CEngineStrings.resw" />
<PRIResource Include="Resources\ar-sa\Resources.resw" />
<PRIResource Include="Resources\az-Latn-AZ\CEngineStrings.resw" />
<PRIResource Include="Resources\az-Latn-AZ\Resources.resw" />
<PRIResource Include="Resources\bg-BG\CEngineStrings.resw" />
<PRIResource Include="Resources\bg-BG\Resources.resw" />
<PRIResource Include="Resources\ca-es\CEngineStrings.resw" />
<PRIResource Include="Resources\ca-es\Resources.resw" />
<PRIResource Include="Resources\cs-cz\CEngineStrings.resw" />
<PRIResource Include="Resources\cs-cz\Resources.resw" />
<PRIResource Include="Resources\da-DK\CEngineStrings.resw" />
<PRIResource Include="Resources\da-DK\Resources.resw" />
<PRIResource Include="Resources\de-de\CEngineStrings.resw" />
<PRIResource Include="Resources\de-de\Resources.resw" />
<PRIResource Include="Resources\el-GR\CEngineStrings.resw" />
<PRIResource Include="Resources\el-GR\Resources.resw" />
<PRIResource Include="Resources\en-gb\CEngineStrings.resw" />
<PRIResource Include="Resources\en-gb\Resources.resw" />
<PRIResource Include="Resources\en-US\CEngineStrings.resw" />
<PRIResource Include="Resources\en-US\Resources.resw">
<SubType>Designer</SubType>
</PRIResource>
<PRIResource Include="Resources\es-es\CEngineStrings.resw" />
<PRIResource Include="Resources\es-es\Resources.resw" />
<PRIResource Include="Resources\es-mx\CEngineStrings.resw" />
<PRIResource Include="Resources\es-mx\resources.resw" />
<PRIResource Include="Resources\et-EE\CEngineStrings.resw" />
<PRIResource Include="Resources\et-EE\Resources.resw" />
<PRIResource Include="Resources\eu-ES\CEngineStrings.resw" />
<PRIResource Include="Resources\eu-ES\Resources.resw" />
<PRIResource Include="Resources\fa-IR\CEngineStrings.resw" />
<PRIResource Include="Resources\fa-IR\Resources.resw" />
<PRIResource Include="Resources\fi-fi\CEngineStrings.resw" />
<PRIResource Include="Resources\fi-fi\Resources.resw" />
<PRIResource Include="Resources\fil-PH\CEngineStrings.resw" />
<PRIResource Include="Resources\fil-PH\Resources.resw" />
<PRIResource Include="Resources\fr-ca\CEngineStrings.resw" />
<PRIResource Include="Resources\fr-ca\resources.resw" />
<PRIResource Include="Resources\fr-fr\CEngineStrings.resw" />
<PRIResource Include="Resources\fr-fr\Resources.resw" />
<PRIResource Include="Resources\gl-ES\CEngineStrings.resw" />
<PRIResource Include="Resources\gl-ES\Resources.resw" />
<PRIResource Include="Resources\he-IL\CEngineStrings.resw" />
<PRIResource Include="Resources\he-IL\Resources.resw" />
<PRIResource Include="Resources\hi-in\CEngineStrings.resw" />
<PRIResource Include="Resources\hi-in\Resources.resw" />
<PRIResource Include="Resources\hr-HR\CEngineStrings.resw" />
<PRIResource Include="Resources\hr-HR\Resources.resw" />
<PRIResource Include="Resources\hu-HU\CEngineStrings.resw" />
<PRIResource Include="Resources\hu-HU\Resources.resw" />
<PRIResource Include="Resources\id-ID\CEngineStrings.resw" />
<PRIResource Include="Resources\id-ID\Resources.resw" />
<PRIResource Include="Resources\is-IS\CEngineStrings.resw" />
<PRIResource Include="Resources\is-IS\Resources.resw" />
<PRIResource Include="Resources\it-it\CEngineStrings.resw" />
<PRIResource Include="Resources\it-it\Resources.resw" />
<PRIResource Include="Resources\ja-jp\CEngineStrings.resw" />
<PRIResource Include="Resources\ja-jp\Resources.resw" />
<PRIResource Include="Resources\kk-KZ\CEngineStrings.resw" />
<PRIResource Include="Resources\kk-KZ\Resources.resw" />
<PRIResource Include="Resources\km-KH\CEngineStrings.resw" />
<PRIResource Include="Resources\km-KH\Resources.resw" />
<PRIResource Include="Resources\kn-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\kn-IN\Resources.resw" />
<PRIResource Include="Resources\ko-kr\CEngineStrings.resw" />
<PRIResource Include="Resources\ko-kr\Resources.resw" />
<PRIResource Include="Resources\lo-LA\CEngineStrings.resw" />
<PRIResource Include="Resources\lo-LA\Resources.resw" />
<PRIResource Include="Resources\lt-LT\CEngineStrings.resw" />
<PRIResource Include="Resources\lt-LT\Resources.resw" />
<PRIResource Include="Resources\lv-LV\CEngineStrings.resw" />
<PRIResource Include="Resources\lv-LV\Resources.resw" />
<PRIResource Include="Resources\mk-MK\CEngineStrings.resw" />
<PRIResource Include="Resources\mk-MK\Resources.resw" />
<PRIResource Include="Resources\ml-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\ml-IN\Resources.resw" />
<PRIResource Include="Resources\ms-MY\CEngineStrings.resw" />
<PRIResource Include="Resources\ms-MY\Resources.resw" />
<PRIResource Include="Resources\nb-NO\CEngineStrings.resw" />
<PRIResource Include="Resources\nb-NO\Resources.resw" />
<PRIResource Include="Resources\nl-nl\CEngineStrings.resw" />
<PRIResource Include="Resources\nl-nl\Resources.resw" />
<PRIResource Include="Resources\pl-pl\CEngineStrings.resw" />
<PRIResource Include="Resources\pl-pl\Resources.resw" />
<PRIResource Include="Resources\pt-br\CEngineStrings.resw" />
<PRIResource Include="Resources\pt-br\Resources.resw" />
<PRIResource Include="Resources\pt-PT\CEngineStrings.resw" />
<PRIResource Include="Resources\pt-PT\Resources.resw" />
<PRIResource Include="Resources\ro-RO\CEngineStrings.resw" />
<PRIResource Include="Resources\ro-RO\Resources.resw" />
<PRIResource Include="Resources\ru-ru\CEngineStrings.resw" />
<PRIResource Include="Resources\ru-ru\Resources.resw" />
<PRIResource Include="Resources\sk-SK\CEngineStrings.resw" />
<PRIResource Include="Resources\sk-SK\Resources.resw" />
<PRIResource Include="Resources\sl-SI\CEngineStrings.resw" />
<PRIResource Include="Resources\sl-SI\Resources.resw" />
<PRIResource Include="Resources\sq-AL\CEngineStrings.resw" />
<PRIResource Include="Resources\sq-AL\Resources.resw" />
<PRIResource Include="Resources\sr-Latn-RS\CEngineStrings.resw" />
<PRIResource Include="Resources\sr-Latn-RS\Resources.resw" />
<PRIResource Include="Resources\sv-se\CEngineStrings.resw" />
<PRIResource Include="Resources\sv-se\Resources.resw" />
<PRIResource Include="Resources\ta-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\ta-IN\Resources.resw" />
<PRIResource Include="Resources\te-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\te-IN\Resources.resw" />
<PRIResource Include="Resources\th-th\CEngineStrings.resw" />
<PRIResource Include="Resources\th-th\Resources.resw" />
<PRIResource Include="Resources\tr-tr\CEngineStrings.resw" />
<PRIResource Include="Resources\tr-tr\Resources.resw" />
<PRIResource Include="Resources\uk-UA\CEngineStrings.resw" />
<PRIResource Include="Resources\uk-UA\Resources.resw" />
<PRIResource Include="Resources\vi-vn\CEngineStrings.resw" />
<PRIResource Include="Resources\vi-vn\Resources.resw" />
<PRIResource Include="Resources\zh-cn\CEngineStrings.resw" />
<PRIResource Include="Resources\zh-cn\Resources.resw" />
<PRIResource Include="Resources\zh-tw\CEngineStrings.resw" />
<PRIResource Include="Resources\zh-tw\Resources.resw" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="EquationStylePanelControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="AboutFlyout.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Calculator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorProgrammerBitFlipPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorProgrammerOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorProgrammerRadixOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorScientificAngleButtons.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorScientificOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CalculatorStandardOperators.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DateCalculator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DelighterUnitStyles.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\GraphingCalculator\EquationInputArea.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\GraphingCalculator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\GraphingNumPad.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\GraphingSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\HistoryList.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Memory.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\MemoryListItem.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\NumberPad.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\OperatorsPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\StateTriggers\CalculatorProgrammerDisplayPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\SupplementaryResults.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\TitleBar.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\UnitConverter.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.10</Version>
</PackageReference>
<PackageReference Include="Microsoft.UI.Xaml" Version="2.4.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CalcViewModel\CalcViewModel.vcxproj">
<Project>{812d1a7b-b8ac-49e4-8e6d-af5d59500d56}</Project>
<Name>CalcViewModel</Name>
</ProjectReference>
<ProjectReference Include="..\GraphControl\GraphControl.vcxproj">
<Project>{e727a92b-f149-492c-8117-c039a298719b}</Project>
<Name>GraphControl</Name>
</ProjectReference>
<ProjectReference Include="..\TraceLogging\TraceLogging.vcxproj">
<Project>{fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed}</Project>
<Name>TraceLogging</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Assets\CalcMDL2.ttf" />
<None Include="WindowsDev_TemporaryKey.pfx" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<!-- Override MSBuild target to workaround VS bug with building using framework packages -->
<Target Name="_GenerateAdditionalFrameworkSDKReference">
<ItemGroup>
<_IntermediateFrameworkSdkReference Include="@(AppxPackageRegistration)" Condition="'@(AppxPackageRegistration)' != ''&#xD;&#xA; AND ('$(Configuration)' == '%(AppxPackageRegistration.Configuration)' OR '%(AppxPackageRegistration.Configuration)' == '')&#xD;&#xA; AND ('$(PlatformTarget)' == '%(AppxPackageRegistration.Architecture)' OR '%(AppxPackageRegistration.Configuration)' == '')">
<SDKName Condition="%(AppxPackageRegistration.Name) != ''">%(AppxPackageRegistration.Name)</SDKName>
<SDKName Condition="%(AppxPackageRegistration.Name) == ''">%(AppxPackageRegistration.Filename)</SDKName>
<TargetedSDKConfiguration>%(AppxPackageRegistration.Configuration)</TargetedSDKConfiguration>
<TargetedSDKArchitecture>%(AppxPackageRegistration.Architecture)</TargetedSDKArchitecture>
<AppxLocation>%(AppxPackageRegistration.Identity)</AppxLocation>
</_IntermediateFrameworkSdkReference>
<FrameworkSdkReference Include="@(_IntermediateFrameworkSdkReference)">
<FrameworkIdentity>Name = %(_IntermediateFrameworkSdkReference.SDKName), MinVersion = %(_IntermediateFrameworkSdkReference.Version), Publisher = %(_IntermediateFrameworkSdkReference.Publisher)</FrameworkIdentity>
</FrameworkSdkReference>
</ItemGroup>
</Target>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<Import Project="$(SolutionDir)build\Calculator.StampAssemblyInfo.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,10 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#define APP_FILE_NAME "Calculator"
#define APP_FILE_IS_EXE
#define APP_PRODUCT_NAME "Microsoft Calculator"
#define APP_COMPANY_NAME "Microsoft Corporation"
#define APP_COPYRIGHT "\251 Microsoft Corporation. All rights reserved."
#include "../build/appversion.rc"

View File

@@ -1,969 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{9447424a-0e05-4911-beb8-e0354405f39a}</ProjectGuid>
<RootNamespace>CalculatorApp</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<!-- We want to manually control the MinVersion/MaxVersionTested in the manifest so turn of the replacement. -->
<AppxOSMinVersionReplaceManifestVersion>false</AppxOSMinVersionReplaceManifestVersion>
<AppxOSMaxVersionTestedReplaceManifestVersion>false</AppxOSMaxVersionTestedReplaceManifestVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<AppxDefaultResourceQualifierUAP_Contrast>black</AppxDefaultResourceQualifierUAP_Contrast>
<AppxBundle>Always</AppxBundle>
<PackageCertificateKeyFile>WindowsDev_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- This has to be exactly in this place for this to work -->
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup>
<Import Project="$(SolutionDir)\GraphControl\GraphingImplOverrides.props" Condition="Exists('$(SolutionDir)\GraphControl\GraphingImplOverrides.props')" />
</ImportGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;$(VC_ReferencesPath_VC_ARM)\pgort.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;$(VC_ReferencesPath_VC_ARM)\pgort.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;$(VC_ReferencesPath_VC_x86)\pgort.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;$(VC_ReferencesPath_VC_x64)\pgort.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(IsStoreBuild)' == 'True'">
<ClCompile>
<AdditionalOptions>/DSEND_DIAGNOSTICS /DIS_STORE_BUILD %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<AppVersion Condition="'$(AppVersion)' == ''">0.0.0.0</AppVersion>
</PropertyGroup>
<PropertyGroup>
<GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
</PropertyGroup>
<ItemGroup>
<ResourceCompile Include="Calculator.rc" PreprocessorDefinitions="%(PreprocessorDefinitions);APP_VERSION_MAJOR=$(AppVersion.Split(`.`)[0]);APP_VERSION_MINOR=$(AppVersion.Split(`.`)[1]);APP_VERSION_BUILD=$(AppVersion.Split(`.`)[2]);APP_VERSION_REVISION=$(AppVersion.Split(`.`)[3])" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AboutFlyout.xaml.h">
<DependentUpon>AboutFlyout.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Common\AppLifecycleLogger.h" />
<ClInclude Include="Common\KeyboardShortcutManager.h" />
<ClInclude Include="Common\ValidatingConverters.h" />
<ClInclude Include="Common\ViewState.h" />
<ClInclude Include="Controls\CalculationResultAutomationPeer.h" />
<ClInclude Include="Controls\MathRichEditBox.h" />
<ClInclude Include="Controls\OverflowTextBlockAutomationPeer.h" />
<ClInclude Include="Common\AlwaysSelectedCollectionView.h" />
<ClInclude Include="Controls\CalculationResult.h" />
<ClInclude Include="Controls\CalculatorButton.h" />
<ClInclude Include="Controls\FlipButtons.h" />
<ClInclude Include="Controls\OverflowTextBlock.h" />
<ClInclude Include="Controls\RadixButton.h" />
<ClInclude Include="Controls\SupplementaryItemsControl.h" />
<ClInclude Include="Converters\BooleanNegationConverter.h" />
<ClInclude Include="Converters\BooleanToVisibilityConverter.h" />
<ClInclude Include="Converters\ExpressionItemTemplateSelector.h" />
<ClInclude Include="Converters\ItemSizeToVisibilityConverter.h" />
<ClInclude Include="Converters\RadixToStringConverter.h" />
<ClInclude Include="Converters\VisibilityNegationConverter.h" />
<ClInclude Include="Controls\HorizontalNoOverflowStackPanel.h" />
<ClInclude Include="Controls\OperatorPanelListView.h" />
<ClInclude Include="Controls\OperatorPanelButton.h" />
<ClInclude Include="Controls\EquationTextBox.h" />
<ClInclude Include="Utils\DispatcherTimerDelayer.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="App.xaml.h">
<DependentUpon>App.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="EquationStylePanelControl.xaml.h">
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="TemplateSelectors\KeyGraphFeaturesTemplateSelector.h" />
<ClInclude Include="Utils\VisualTree.h" />
<ClInclude Include="Views\Calculator.xaml.h">
<DependentUpon>Views\Calculator.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorProgrammerBitFlipPanel.xaml.h">
<DependentUpon>Views\CalculatorProgrammerBitFlipPanel.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorProgrammerDisplayPanel.xaml.h">
<DependentUpon>Views\CalculatorProgrammerDisplayPanel.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorProgrammerOperators.xaml.h">
<DependentUpon>Views\CalculatorProgrammerOperators.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorProgrammerRadixOperators.xaml.h">
<DependentUpon>Views\CalculatorProgrammerRadixOperators.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorScientificAngleButtons.xaml.h">
<DependentUpon>Views\CalculatorScientificAngleButtons.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorScientificOperators.xaml.h">
<DependentUpon>Views\CalculatorScientificOperators.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\CalculatorStandardOperators.xaml.h">
<DependentUpon>Views\CalculatorStandardOperators.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\GraphingCalculator\EquationInputArea.xaml.h">
<DependentUpon>Views\GraphingCalculator\EquationInputArea.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\GraphingCalculator\GraphingCalculator.xaml.h">
<DependentUpon>Views\GraphingCalculator\GraphingCalculator.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\GraphingCalculator\GraphingSettings.xaml.h">
<DependentUpon>Views\GraphingCalculator\GraphingSettings.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.h">
<DependentUpon>Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\GraphingCalculator\GraphingNumPad.xaml.h">
<DependentUpon>Views\GraphingCalculator\GraphingNumPad.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\HistoryList.xaml.h">
<DependentUpon>Views\HistoryList.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\MainPage.xaml.h">
<DependentUpon>Views\MainPage.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\Memory.xaml.h">
<DependentUpon>Views\Memory.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\MemoryListItem.xaml.h">
<DependentUpon>Views\MemoryListItem.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\NumberPad.xaml.h">
<DependentUpon>Views\NumberPad.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\OperatorsPanel.xaml.h">
<DependentUpon>Views\OperatorsPanel.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\StateTriggers\AspectRatioTrigger.h" />
<ClInclude Include="Views\StateTriggers\ControlSizeTrigger.h" />
<ClInclude Include="Views\SupplementaryResults.xaml.h">
<DependentUpon>Views\SupplementaryResults.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\DateCalculator.xaml.h">
<DependentUpon>Views\DateCalculator.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\TitleBar.xaml.h">
<DependentUpon>Views\TitleBar.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Views\UnitConverter.xaml.h">
<DependentUpon>Views\UnitConverter.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="WindowFrameService.h" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="AboutFlyout.xaml" />
<Page Include="EquationStylePanelControl.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Calculator.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Views\CalculatorProgrammerBitFlipPanel.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Views\CalculatorProgrammerDisplayPanel.xaml" />
<Page Include="Views\CalculatorProgrammerOperators.xaml" />
<Page Include="Views\CalculatorProgrammerRadixOperators.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Views\CalculatorScientificAngleButtons.xaml" />
<Page Include="Views\CalculatorScientificOperators.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Views\CalculatorStandardOperators.xaml" />
<Page Include="Views\DelighterUnitStyles.xaml" />
<Page Include="Views\GraphingCalculator\EquationInputArea.xaml" />
<Page Include="Views\GraphingCalculator\GraphingCalculator.xaml" />
<Page Include="Views\GraphingCalculator\GraphingSettings.xaml" />
<Page Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml" />
<Page Include="Views\GraphingCalculator\GraphingNumPad.xaml" />
<Page Include="Views\HistoryList.xaml" />
<Page Include="Views\MainPage.xaml" />
<Page Include="Views\Memory.xaml" />
<Page Include="Views\MemoryListItem.xaml" />
<Page Include="Views\NumberPad.xaml" />
<Page Include="Views\OperatorsPanel.xaml" />
<Page Include="Views\SupplementaryResults.xaml" />
<Page Include="Views\DateCalculator.xaml" />
<Page Include="Views\TitleBar.xaml" />
<Page Include="Views\UnitConverter.xaml" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="WindowsDev_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AboutFlyout.xaml.cpp">
<DependentUpon>AboutFlyout.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="App.xaml.cpp">
<DependentUpon>App.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Common\AppLifecycleLogger.cpp" />
<ClCompile Include="Common\KeyboardShortcutManager.cpp" />
<ClCompile Include="Common\ViewState.cpp" />
<ClCompile Include="Controls\CalculationResultAutomationPeer.cpp" />
<ClCompile Include="Controls\MathRichEditBox.cpp" />
<ClCompile Include="Controls\OverflowTextBlockAutomationPeer.cpp" />
<ClCompile Include="Controls\CalculationResult.cpp" />
<ClCompile Include="Controls\CalculatorButton.cpp" />
<ClCompile Include="Controls\FlipButtons.cpp" />
<ClCompile Include="Controls\OverflowTextBlock.cpp" />
<ClCompile Include="Controls\RadixButton.cpp" />
<ClCompile Include="Controls\SupplementaryItemsControl.cpp" />
<ClCompile Include="Converters\BooleanNegationConverter.cpp" />
<ClCompile Include="Converters\BooleanToVisibilityConverter.cpp" />
<ClCompile Include="Converters\ExpressionItemTemplateSelector.cpp" />
<ClCompile Include="Converters\ItemSizeToVisibilityConverter.cpp" />
<ClCompile Include="Converters\RadixToStringConverter.cpp" />
<ClCompile Include="Converters\VisibilityNegationConverter.cpp" />
<ClCompile Include="Controls\HorizontalNoOverflowStackPanel.cpp" />
<ClCompile Include="Controls\OperatorPanelListView.cpp" />
<ClCompile Include="Controls\OperatorPanelButton.cpp" />
<ClCompile Include="Controls\EquationTextBox.cpp" />
<ClCompile Include="Utils\DispatcherTimerDelayer.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="EquationStylePanelControl.xaml.cpp">
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="TemplateSelectors\KeyGraphFeaturesTemplateSelector.cpp" />
<ClCompile Include="Utils\VisualTree.cpp" />
<ClCompile Include="Views\Calculator.xaml.cpp">
<DependentUpon>Views\Calculator.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorProgrammerBitFlipPanel.xaml.cpp">
<DependentUpon>Views\CalculatorProgrammerBitFlipPanel.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorProgrammerDisplayPanel.xaml.cpp">
<DependentUpon>Views\CalculatorProgrammerDisplayPanel.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorProgrammerOperators.xaml.cpp">
<DependentUpon>Views\CalculatorProgrammerOperators.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorProgrammerRadixOperators.xaml.cpp">
<DependentUpon>Views\CalculatorProgrammerRadixOperators.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorScientificAngleButtons.xaml.cpp">
<DependentUpon>Views\CalculatorScientificAngleButtons.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorScientificOperators.xaml.cpp">
<DependentUpon>Views\CalculatorScientificOperators.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\CalculatorStandardOperators.xaml.cpp">
<DependentUpon>Views\CalculatorStandardOperators.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\GraphingCalculator\EquationInputArea.xaml.cpp">
<DependentUpon>Views\GraphingCalculator\EquationInputArea.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\GraphingCalculator\GraphingCalculator.xaml.cpp">
<DependentUpon>Views\GraphingCalculator\GraphingCalculator.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\GraphingCalculator\GraphingSettings.xaml.cpp">
<DependentUpon>Views\GraphingCalculator\GraphingSettings.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.cpp">
<DependentUpon>Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\GraphingCalculator\GraphingNumPad.xaml.cpp">
<DependentUpon>Views\GraphingCalculator\GraphingNumPad.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\HistoryList.xaml.cpp">
<DependentUpon>Views\HistoryList.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\MainPage.xaml.cpp">
<DependentUpon>Views\MainPage.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\Memory.xaml.cpp">
<DependentUpon>Views\Memory.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\MemoryListItem.xaml.cpp">
<DependentUpon>Views\MemoryListItem.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\NumberPad.xaml.cpp">
<DependentUpon>Views\NumberPad.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\OperatorsPanel.xaml.cpp">
<DependentUpon>Views\OperatorsPanel.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\StateTriggers\AspectRatioTrigger.cpp" />
<ClCompile Include="Views\StateTriggers\ControlSizeTrigger.cpp" />
<ClCompile Include="Views\SupplementaryResults.xaml.cpp">
<DependentUpon>Views\SupplementaryResults.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\DateCalculator.xaml.cpp">
<DependentUpon>Views\DateCalculator.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\TitleBar.xaml.cpp">
<DependentUpon>Views\TitleBar.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Views\UnitConverter.xaml.cpp">
<DependentUpon>Views\UnitConverter.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="WindowFrameService.cpp" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Resources\af-ZA\CEngineStrings.resw" />
<PRIResource Include="Resources\af-ZA\Resources.resw" />
<PRIResource Include="Resources\am-et\CEngineStrings.resw" />
<PRIResource Include="Resources\am-et\Resources.resw" />
<PRIResource Include="Resources\ar-sa\CEngineStrings.resw" />
<PRIResource Include="Resources\ar-sa\Resources.resw" />
<PRIResource Include="Resources\az-Latn-AZ\CEngineStrings.resw" />
<PRIResource Include="Resources\az-Latn-AZ\Resources.resw" />
<PRIResource Include="Resources\bg-BG\CEngineStrings.resw" />
<PRIResource Include="Resources\bg-BG\Resources.resw" />
<PRIResource Include="Resources\ca-es\CEngineStrings.resw" />
<PRIResource Include="Resources\ca-es\Resources.resw" />
<PRIResource Include="Resources\cs-cz\CEngineStrings.resw" />
<PRIResource Include="Resources\cs-cz\Resources.resw" />
<PRIResource Include="Resources\da-DK\CEngineStrings.resw" />
<PRIResource Include="Resources\da-DK\Resources.resw" />
<PRIResource Include="Resources\de-de\CEngineStrings.resw" />
<PRIResource Include="Resources\de-de\Resources.resw" />
<PRIResource Include="Resources\el-GR\CEngineStrings.resw" />
<PRIResource Include="Resources\el-GR\Resources.resw" />
<PRIResource Include="Resources\en-gb\CEngineStrings.resw" />
<PRIResource Include="Resources\en-gb\Resources.resw" />
<PRIResource Include="Resources\en-US\CEngineStrings.resw" />
<PRIResource Include="Resources\en-US\Resources.resw">
<SubType>Designer</SubType>
</PRIResource>
<PRIResource Include="Resources\es-es\CEngineStrings.resw" />
<PRIResource Include="Resources\es-es\Resources.resw" />
<PRIResource Include="Resources\es-mx\CEngineStrings.resw" />
<PRIResource Include="Resources\es-mx\resources.resw" />
<PRIResource Include="Resources\et-EE\CEngineStrings.resw" />
<PRIResource Include="Resources\et-EE\Resources.resw" />
<PRIResource Include="Resources\eu-ES\CEngineStrings.resw" />
<PRIResource Include="Resources\eu-ES\Resources.resw" />
<PRIResource Include="Resources\fa-IR\CEngineStrings.resw" />
<PRIResource Include="Resources\fa-IR\Resources.resw" />
<PRIResource Include="Resources\fi-fi\CEngineStrings.resw" />
<PRIResource Include="Resources\fi-fi\Resources.resw" />
<PRIResource Include="Resources\fil-PH\CEngineStrings.resw" />
<PRIResource Include="Resources\fil-PH\Resources.resw" />
<PRIResource Include="Resources\fr-ca\CEngineStrings.resw" />
<PRIResource Include="Resources\fr-ca\resources.resw" />
<PRIResource Include="Resources\fr-fr\CEngineStrings.resw" />
<PRIResource Include="Resources\fr-fr\Resources.resw" />
<PRIResource Include="Resources\gl-ES\CEngineStrings.resw" />
<PRIResource Include="Resources\gl-ES\Resources.resw" />
<PRIResource Include="Resources\he-IL\CEngineStrings.resw" />
<PRIResource Include="Resources\he-IL\Resources.resw" />
<PRIResource Include="Resources\hi-in\CEngineStrings.resw" />
<PRIResource Include="Resources\hi-in\Resources.resw" />
<PRIResource Include="Resources\hr-HR\CEngineStrings.resw" />
<PRIResource Include="Resources\hr-HR\Resources.resw" />
<PRIResource Include="Resources\hu-HU\CEngineStrings.resw" />
<PRIResource Include="Resources\hu-HU\Resources.resw" />
<PRIResource Include="Resources\id-ID\CEngineStrings.resw" />
<PRIResource Include="Resources\id-ID\Resources.resw" />
<PRIResource Include="Resources\is-IS\CEngineStrings.resw" />
<PRIResource Include="Resources\is-IS\Resources.resw" />
<PRIResource Include="Resources\it-it\CEngineStrings.resw" />
<PRIResource Include="Resources\it-it\Resources.resw" />
<PRIResource Include="Resources\ja-jp\CEngineStrings.resw" />
<PRIResource Include="Resources\ja-jp\Resources.resw" />
<PRIResource Include="Resources\kk-KZ\CEngineStrings.resw" />
<PRIResource Include="Resources\kk-KZ\Resources.resw" />
<PRIResource Include="Resources\km-KH\CEngineStrings.resw" />
<PRIResource Include="Resources\km-KH\Resources.resw" />
<PRIResource Include="Resources\kn-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\kn-IN\Resources.resw" />
<PRIResource Include="Resources\ko-kr\CEngineStrings.resw" />
<PRIResource Include="Resources\ko-kr\Resources.resw" />
<PRIResource Include="Resources\lo-LA\CEngineStrings.resw" />
<PRIResource Include="Resources\lo-LA\Resources.resw" />
<PRIResource Include="Resources\lt-LT\CEngineStrings.resw" />
<PRIResource Include="Resources\lt-LT\Resources.resw" />
<PRIResource Include="Resources\lv-LV\CEngineStrings.resw" />
<PRIResource Include="Resources\lv-LV\Resources.resw" />
<PRIResource Include="Resources\mk-MK\CEngineStrings.resw" />
<PRIResource Include="Resources\mk-MK\Resources.resw" />
<PRIResource Include="Resources\ml-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\ml-IN\Resources.resw" />
<PRIResource Include="Resources\ms-MY\CEngineStrings.resw" />
<PRIResource Include="Resources\ms-MY\Resources.resw" />
<PRIResource Include="Resources\nb-NO\CEngineStrings.resw" />
<PRIResource Include="Resources\nb-NO\Resources.resw" />
<PRIResource Include="Resources\nl-nl\CEngineStrings.resw" />
<PRIResource Include="Resources\nl-nl\Resources.resw" />
<PRIResource Include="Resources\pl-pl\CEngineStrings.resw" />
<PRIResource Include="Resources\pl-pl\Resources.resw" />
<PRIResource Include="Resources\pt-br\CEngineStrings.resw" />
<PRIResource Include="Resources\pt-br\Resources.resw" />
<PRIResource Include="Resources\pt-PT\CEngineStrings.resw" />
<PRIResource Include="Resources\pt-PT\Resources.resw" />
<PRIResource Include="Resources\ro-RO\CEngineStrings.resw" />
<PRIResource Include="Resources\ro-RO\Resources.resw" />
<PRIResource Include="Resources\ru-ru\CEngineStrings.resw" />
<PRIResource Include="Resources\ru-ru\Resources.resw" />
<PRIResource Include="Resources\sk-SK\CEngineStrings.resw" />
<PRIResource Include="Resources\sk-SK\Resources.resw" />
<PRIResource Include="Resources\sl-SI\CEngineStrings.resw" />
<PRIResource Include="Resources\sl-SI\Resources.resw" />
<PRIResource Include="Resources\sq-AL\CEngineStrings.resw" />
<PRIResource Include="Resources\sq-AL\Resources.resw" />
<PRIResource Include="Resources\sr-Latn-RS\CEngineStrings.resw" />
<PRIResource Include="Resources\sr-Latn-RS\Resources.resw" />
<PRIResource Include="Resources\sv-se\CEngineStrings.resw" />
<PRIResource Include="Resources\sv-se\Resources.resw" />
<PRIResource Include="Resources\ta-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\ta-IN\Resources.resw" />
<PRIResource Include="Resources\te-IN\CEngineStrings.resw" />
<PRIResource Include="Resources\te-IN\Resources.resw" />
<PRIResource Include="Resources\th-th\CEngineStrings.resw" />
<PRIResource Include="Resources\th-th\Resources.resw" />
<PRIResource Include="Resources\tr-tr\CEngineStrings.resw" />
<PRIResource Include="Resources\tr-tr\Resources.resw" />
<PRIResource Include="Resources\uk-UA\CEngineStrings.resw" />
<PRIResource Include="Resources\uk-UA\Resources.resw" />
<PRIResource Include="Resources\vi-vn\CEngineStrings.resw" />
<PRIResource Include="Resources\vi-vn\Resources.resw" />
<PRIResource Include="Resources\zh-cn\CEngineStrings.resw" />
<PRIResource Include="Resources\zh-cn\Resources.resw" />
<PRIResource Include="Resources\zh-tw\CEngineStrings.resw" />
<PRIResource Include="Resources\zh-tw\Resources.resw" />
</ItemGroup>
<ItemGroup Condition="'$(IsStoreBuild)' == 'True'">
<Image Include="Assets\CalculatorAppList.scale-100.png" />
<Image Include="Assets\CalculatorAppList.scale-125.png" />
<Image Include="Assets\CalculatorAppList.scale-150.png" />
<Image Include="Assets\CalculatorAppList.scale-200.png" />
<Image Include="Assets\CalculatorAppList.scale-400.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated_contrast-white.png" />
<Image Include="Assets\CalculatorLargeTile.scale-100.png" />
<Image Include="Assets\CalculatorLargeTile.scale-125.png" />
<Image Include="Assets\CalculatorLargeTile.scale-150.png" />
<Image Include="Assets\CalculatorLargeTile.scale-200.png" />
<Image Include="Assets\CalculatorLargeTile.scale-400.png" />
<Image Include="Assets\CalculatorMedTile.scale-100.png" />
<Image Include="Assets\CalculatorMedTile.scale-125.png" />
<Image Include="Assets\CalculatorMedTile.scale-150.png" />
<Image Include="Assets\CalculatorMedTile.scale-200.png" />
<Image Include="Assets\CalculatorMedTile.scale-400.png" />
<Image Include="Assets\CalculatorSmallTile.scale-100.png" />
<Image Include="Assets\CalculatorSmallTile.scale-125.png" />
<Image Include="Assets\CalculatorSmallTile.scale-150.png" />
<Image Include="Assets\CalculatorSmallTile.scale-200.png" />
<Image Include="Assets\CalculatorSmallTile.scale-400.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-100.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-125.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-150.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-200.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-400.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-100.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-125.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-150.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-200.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-400.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-400_contrast-white.png" />
<Image Include="Assets\CalculatorWideTile.scale-100.png" />
<Image Include="Assets\CalculatorWideTile.scale-125.png" />
<Image Include="Assets\CalculatorWideTile.scale-150.png" />
<Image Include="Assets\CalculatorWideTile.scale-200.png" />
<Image Include="Assets\CalculatorWideTile.scale-400.png" />
</ItemGroup>
<ItemGroup>
<Image Include="Assets\CalculatorAppList.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.scale-400_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-16_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-20_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-24_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-256_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-30_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-32_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-36_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-40_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-48_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-60_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-64_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-72_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-80_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_altform-lightunplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_altform-unplated.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_altform-unplated_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_altform-unplated_contrast-white.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_contrast-black.png" />
<Image Include="Assets\CalculatorAppList.targetsize-96_contrast-white.png" />
<Image Include="Assets\CalculatorLargeTile.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorLargeTile.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorLargeTile.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorLargeTile.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorLargeTile.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorLargeTile.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorLargeTile.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorLargeTile.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorLargeTile.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorLargeTile.scale-400_contrast-white.png" />
<Image Include="Assets\CalculatorMedTile.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorMedTile.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorMedTile.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorMedTile.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorMedTile.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorMedTile.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorMedTile.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorMedTile.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorMedTile.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorMedTile.scale-400_contrast-white.png" />
<Image Include="Assets\CalculatorSmallTile.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorSmallTile.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorSmallTile.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorSmallTile.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorSmallTile.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorSmallTile.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorSmallTile.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorSmallTile.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorSmallTile.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorSmallTile.scale-400_contrast-white.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-100_altform-colorful.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-125_altform-colorful.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-150_altform-colorful.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-200_altform-colorful.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-400_altform-colorful.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorSplashScreen.scale-400_contrast-white.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorStoreLogo.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorWideTile.scale-100_contrast-black.png" />
<Image Include="Assets\CalculatorWideTile.scale-100_contrast-white.png" />
<Image Include="Assets\CalculatorWideTile.scale-125_contrast-black.png" />
<Image Include="Assets\CalculatorWideTile.scale-125_contrast-white.png" />
<Image Include="Assets\CalculatorWideTile.scale-150_contrast-black.png" />
<Image Include="Assets\CalculatorWideTile.scale-150_contrast-white.png" />
<Image Include="Assets\CalculatorWideTile.scale-200_contrast-black.png" />
<Image Include="Assets\CalculatorWideTile.scale-200_contrast-white.png" />
<Image Include="Assets\CalculatorWideTile.scale-400_contrast-black.png" />
<Image Include="Assets\CalculatorWideTile.scale-400_contrast-white.png" />
<Image Include="Assets\Date.targetsize-16_contrast-black.png" />
<Image Include="Assets\Date.targetsize-16_contrast-white.png" />
<Image Include="Assets\Date.targetsize-20_contrast-black.png" />
<Image Include="Assets\Date.targetsize-20_contrast-white.png" />
<Image Include="Assets\Date.targetsize-24_contrast-black.png" />
<Image Include="Assets\Date.targetsize-24_contrast-white.png" />
<Image Include="Assets\Date.targetsize-32_contrast-black.png" />
<Image Include="Assets\Date.targetsize-32_contrast-white.png" />
<Image Include="Assets\Date.targetsize-64_contrast-black.png" />
<Image Include="Assets\Date.targetsize-64_contrast-white.png" />
<Image Include="Assets\Graphing.targetsize-16.png" />
<Image Include="Assets\Graphing.targetsize-16_contrast-black.png" />
<Image Include="Assets\Graphing.targetsize-16_contrast-white.png" />
<Image Include="Assets\Graphing.targetsize-20.png" />
<Image Include="Assets\Graphing.targetsize-20_contrast-black.png" />
<Image Include="Assets\Graphing.targetsize-20_contrast-white.png" />
<Image Include="Assets\Graphing.targetsize-24.png" />
<Image Include="Assets\Graphing.targetsize-24_contrast-black.png" />
<Image Include="Assets\Graphing.targetsize-24_contrast-white.png" />
<Image Include="Assets\Graphing.targetsize-32.png" />
<Image Include="Assets\Graphing.targetsize-32_contrast-black.png" />
<Image Include="Assets\Graphing.targetsize-32_contrast-white.png" />
<Image Include="Assets\Graphing.targetsize-64.png" />
<Image Include="Assets\Graphing.targetsize-64_contrast-black.png" />
<Image Include="Assets\Graphing.targetsize-64_contrast-white.png" />
<Image Include="Assets\Programmer.targetsize-16_contrast-black.png" />
<Image Include="Assets\Programmer.targetsize-16_contrast-white.png" />
<Image Include="Assets\Programmer.targetsize-20_contrast-black.png" />
<Image Include="Assets\Programmer.targetsize-20_contrast-white.png" />
<Image Include="Assets\Programmer.targetsize-24_contrast-black.png" />
<Image Include="Assets\Programmer.targetsize-24_contrast-white.png" />
<Image Include="Assets\Programmer.targetsize-32_contrast-black.png" />
<Image Include="Assets\Programmer.targetsize-32_contrast-white.png" />
<Image Include="Assets\Programmer.targetsize-64_contrast-black.png" />
<Image Include="Assets\Programmer.targetsize-64_contrast-white.png" />
<Image Include="Assets\Scientific.targetsize-16_contrast-black.png" />
<Image Include="Assets\Scientific.targetsize-16_contrast-white.png" />
<Image Include="Assets\Scientific.targetsize-20_contrast-black.png" />
<Image Include="Assets\Scientific.targetsize-20_contrast-white.png" />
<Image Include="Assets\Scientific.targetsize-24_contrast-black.png" />
<Image Include="Assets\Scientific.targetsize-24_contrast-white.png" />
<Image Include="Assets\Scientific.targetsize-32_contrast-black.png" />
<Image Include="Assets\Scientific.targetsize-32_contrast-white.png" />
<Image Include="Assets\Scientific.targetsize-64_contrast-black.png" />
<Image Include="Assets\Scientific.targetsize-64_contrast-white.png" />
<Image Include="Assets\Standard.targetsize-16_contrast-black.png" />
<Image Include="Assets\Standard.targetsize-16_contrast-white.png" />
<Image Include="Assets\Standard.targetsize-20_contrast-black.png" />
<Image Include="Assets\Standard.targetsize-20_contrast-white.png" />
<Image Include="Assets\Standard.targetsize-24_contrast-black.png" />
<Image Include="Assets\Standard.targetsize-24_contrast-white.png" />
<Image Include="Assets\Standard.targetsize-32_contrast-black.png" />
<Image Include="Assets\Standard.targetsize-32_contrast-white.png" />
<Image Include="Assets\Standard.targetsize-64_contrast-black.png" />
<Image Include="Assets\Standard.targetsize-64_contrast-white.png" />
</ItemGroup>
<ItemGroup>
<Font Include="Assets\CalcMDL2.ttf">
<DeploymentContent>true</DeploymentContent>
</Font>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CalcViewModel\CalcViewModel.vcxproj">
<Project>{90e9761d-9262-4773-942d-caeae75d7140}</Project>
</ProjectReference>
<ProjectReference Include="..\GraphControl\GraphControl.vcxproj">
<Project>{e727a92b-f149-492c-8117-c039a298719b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<!-- Override MSBuild target to workaround VS bug with building using framework packages -->
<Target Name="_GenerateAdditionalFrameworkSDKReference">
<ItemGroup>
<_IntermediateFrameworkSdkReference Include="@(AppxPackageRegistration)" Condition="'@(AppxPackageRegistration)' != ''&#xD;&#xA; AND ('$(Configuration)' == '%(AppxPackageRegistration.Configuration)' OR '%(AppxPackageRegistration.Configuration)' == '')&#xD;&#xA; AND ('$(PlatformTarget)' == '%(AppxPackageRegistration.Architecture)' OR '%(AppxPackageRegistration.Configuration)' == '')">
<SDKName Condition="%(AppxPackageRegistration.Name) != ''">%(AppxPackageRegistration.Name)</SDKName>
<SDKName Condition="%(AppxPackageRegistration.Name) == ''">%(AppxPackageRegistration.Filename)</SDKName>
<TargetedSDKConfiguration>%(AppxPackageRegistration.Configuration)</TargetedSDKConfiguration>
<TargetedSDKArchitecture>%(AppxPackageRegistration.Architecture)</TargetedSDKArchitecture>
<AppxLocation>%(AppxPackageRegistration.Identity)</AppxLocation>
</_IntermediateFrameworkSdkReference>
<FrameworkSdkReference Include="@(_IntermediateFrameworkSdkReference)">
<FrameworkIdentity>Name = %(_IntermediateFrameworkSdkReference.SDKName), MinVersion = %(_IntermediateFrameworkSdkReference.Version), Publisher = %(_IntermediateFrameworkSdkReference.Publisher)</FrameworkIdentity>
</FrameworkSdkReference>
</ItemGroup>
</Target>
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.UI.Xaml.2.4.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\packages\Microsoft.UI.Xaml.2.4.3\build\native\Microsoft.UI.Xaml.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see https://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.UI.Xaml.2.4.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.UI.Xaml.2.4.3\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,260 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml.Data;
namespace CalculatorApp
{
namespace Common
{
sealed class AlwaysSelectedCollectionView : Windows.UI.Xaml.DependencyObject, Windows.UI.Xaml.Data.ICollectionView
{
internal AlwaysSelectedCollectionView(IList source)
{
m_currentPosition = -1;
m_source = source;
var observable = source as Windows.UI.Xaml.Interop.IBindableObservableVector;
if (observable != null)
{
observable.VectorChanged += OnSourceBindableVectorChanged;
}
}
public bool MoveCurrentTo(object item)
{
if (item != null)
{
int newCurrentPosition = m_source.IndexOf(item);
if (newCurrentPosition != -1)
{
m_currentPosition = newCurrentPosition;
CurrentChanged?.Invoke(this, null);
return true;
}
}
// The item is not in the collection
// We're going to schedule a call back later so we
// restore the selection to the way we wanted it to begin with
if (m_currentPosition >= 0 && m_currentPosition < m_source.Count)
{
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new Windows.UI.Core.DispatchedHandler(() =>
{
CurrentChanged?.Invoke(this, null);
})).AsTask().Wait();
}
return false;
}
public bool MoveCurrentToPosition(int index)
{
if (index < 0 || index >= m_source.Count)
{
return false;
}
m_currentPosition = index;
CurrentChanged?.Invoke(this, null);
return true;
}
#region no implementations
public bool MoveCurrentToFirst()
{
throw new NotImplementedException();
}
public bool MoveCurrentToLast()
{
throw new NotImplementedException();
}
public bool MoveCurrentToNext()
{
throw new NotImplementedException();
}
public bool MoveCurrentToPrevious()
{
throw new NotImplementedException();
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
throw new NotImplementedException();
}
public void Insert(int index, object item)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
public void Add(object item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(object item)
{
throw new NotImplementedException();
}
public void CopyTo(object[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(object item)
{
throw new NotImplementedException();
}
public bool IsReadOnly => throw new NotImplementedException();
#endregion no implementations
public object this[int index]
{
get
{
return m_source[index];
}
set => throw new NotImplementedException();
}
public int Count
{
get
{
return m_source.Count;
}
}
public IObservableVector<object> CollectionGroups
{
get
{
return (IObservableVector<object>)new List<object>();
}
}
public object CurrentItem
{
get
{
if (m_currentPosition >= 0 && m_currentPosition < m_source.Count)
{
return m_source[m_currentPosition];
}
return null;
}
}
public int CurrentPosition
{
get
{
return m_currentPosition;
}
}
public bool HasMoreItems
{
get
{
return false;
}
}
public bool IsCurrentAfterLast
{
get
{
return m_currentPosition >= m_source.Count;
}
}
public bool IsCurrentBeforeFirst
{
get
{
return m_currentPosition < 0;
}
}
public int IndexOf(object item)
{
return m_source.IndexOf(item);
}
public IEnumerator<object> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
// Event handlers
void OnSourceBindableVectorChanged(Windows.UI.Xaml.Interop.IBindableObservableVector source, object e)
{
Windows.Foundation.Collections.IVectorChangedEventArgs args = (Windows.Foundation.Collections.IVectorChangedEventArgs)e;
VectorChanged?.Invoke(this, args);
}
public event EventHandler<object> CurrentChanged;
public event VectorChangedEventHandler<object> VectorChanged;
public event CurrentChangingEventHandler CurrentChanging
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
IList m_source;
int m_currentPosition;
}
public sealed class AlwaysSelectedCollectionViewConverter : Windows.UI.Xaml.Data.IValueConverter
{
public AlwaysSelectedCollectionViewConverter()
{
}
public object Convert(object value, Type targetType, object parameter, string language)
{
var result = value as IList;
if (result != null)
{
return new AlwaysSelectedCollectionView(result);
}
return Windows.UI.Xaml.DependencyProperty.UnsetValue; // Can't convert
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
}
}
}
}

View File

@@ -1,293 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Common
{
ref class AlwaysSelectedCollectionView sealed : public Windows::UI::Xaml::DependencyObject, public Windows::UI::Xaml::Data::ICollectionView
{
internal : AlwaysSelectedCollectionView(Windows::UI::Xaml::Interop::IBindableVector ^ source)
: m_currentPosition(-1)
{
m_source = source;
Windows::UI::Xaml::Interop::IBindableObservableVector ^ observable =
dynamic_cast<Windows::UI::Xaml::Interop::IBindableObservableVector ^>(source);
if (observable)
{
observable->VectorChanged += ref new Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler(
this, &AlwaysSelectedCollectionView::OnSourceBindableVectorChanged);
}
}
private:
// ICollectionView
// Not implemented methods
virtual Windows::Foundation::IAsyncOperation<
Windows::UI::Xaml::Data::LoadMoreItemsResult> ^ LoadMoreItemsAsync(unsigned int) = Windows::UI::Xaml::Data::ICollectionView::LoadMoreItemsAsync
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToFirst() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToFirst
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToLast() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToLast
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToNext() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToNext
{
throw ref new Platform::NotImplementedException();
}
virtual bool MoveCurrentToPrevious() = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPrevious
{
throw ref new Platform::NotImplementedException();
}
property Windows::Foundation::Collections::IObservableVector<Platform::Object ^> ^ CollectionGroups {
virtual Windows::Foundation::Collections::IObservableVector<
Platform::Object ^> ^ get() = Windows::UI::Xaml::Data::ICollectionView::CollectionGroups::get
{
return ref new Platform::Collections::Vector<Platform::Object ^>();
}
} property bool HasMoreItems
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::HasMoreItems::get
{
return false;
}
}
// Implementented methods
virtual bool MoveCurrentTo(Platform::Object ^ item) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentTo
{
if (item)
{
unsigned int newCurrentPosition = 0;
bool result = m_source->IndexOf(item, &newCurrentPosition);
if (result)
{
m_currentPosition = newCurrentPosition;
m_currentChanged(this, nullptr);
return true;
}
}
// The item is not in the collection
// We're going to schedule a call back later so we
// restore the selection to the way we wanted it to begin with
if (m_currentPosition >= 0 && m_currentPosition < static_cast<int>(m_source->Size))
{
this->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this]() {
m_currentChanged(this, nullptr);
}));
}
return false;
}
virtual bool MoveCurrentToPosition(int index) = Windows::UI::Xaml::Data::ICollectionView::MoveCurrentToPosition
{
if (index < 0 || index >= static_cast<int>(m_source->Size))
{
return false;
}
m_currentPosition = index;
m_currentChanged(this, nullptr);
return true;
}
property Platform::Object^ CurrentItem
{
virtual Platform::Object^ get() = Windows::UI::Xaml::Data::ICollectionView::CurrentItem::get
{
if (m_currentPosition >= 0 && m_currentPosition < static_cast<int>(m_source->Size))
{
return m_source->GetAt(m_currentPosition);
}
return nullptr;
}
}
property int CurrentPosition
{
virtual int get() = Windows::UI::Xaml::Data::ICollectionView::CurrentPosition::get
{
return m_currentPosition;
}
}
property bool IsCurrentAfterLast
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentAfterLast::get
{
return m_currentPosition >= static_cast<int>(m_source->Size);
}
}
property bool IsCurrentBeforeFirst
{
virtual bool get() = Windows::UI::Xaml::Data::ICollectionView::IsCurrentBeforeFirst::get
{
return m_currentPosition < 0;
}
}
event Windows::Foundation::EventHandler<Platform::Object^>^ CurrentChanged
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::Foundation::EventHandler<Platform::Object^>^ handler) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanged::add
{
return m_currentChanged += handler;
}
virtual void remove(Windows::Foundation::EventRegistrationToken token) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanged::remove
{
m_currentChanged -= token;
}
}
event Windows::UI::Xaml::Data::CurrentChangingEventHandler^ CurrentChanging
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::UI::Xaml::Data::CurrentChangingEventHandler^ handler) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanging::add
{
return m_currentChanging += handler;
}
virtual void remove(Windows::Foundation::EventRegistrationToken token) = Windows::UI::Xaml::Data::ICollectionView::CurrentChanging::remove
{
m_currentChanging -= token;
}
}
// IVector<Object^>
// Not implemented methods
virtual void Append(Platform::Object^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object^>::Append
{
throw ref new Platform::NotImplementedException();
}
virtual void Clear() = Windows::Foundation::Collections::IVector<Platform::Object ^>::Clear
{
throw ref new Platform::NotImplementedException();
}
virtual unsigned int GetMany(
unsigned int /*startIndex*/,
Platform::WriteOnlyArray<Platform::Object ^> ^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::GetMany
{
throw ref new Platform::NotImplementedException();
}
virtual Windows::Foundation::Collections::IVectorView<Platform::Object ^> ^ GetView() = Windows::Foundation::Collections::IVector<
Platform::Object ^>::GetView
{
throw ref new Platform::NotImplementedException();
}
virtual void InsertAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::InsertAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAt(unsigned int /*index*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::RemoveAt
{
throw ref new Platform::NotImplementedException();
}
virtual void RemoveAtEnd() = Windows::Foundation::Collections::IVector<Platform::Object ^>::RemoveAtEnd
{
throw ref new Platform::NotImplementedException();
}
virtual void
ReplaceAll(const Platform::Array<Platform::Object ^> ^ /*items*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::ReplaceAll
{
throw ref new Platform::NotImplementedException();
}
virtual void SetAt(unsigned int /*index*/, Platform::Object ^ /*item*/) = Windows::Foundation::Collections::IVector<Platform::Object ^>::SetAt
{
throw ref new Platform::NotImplementedException();
}
// Implemented methods
virtual Platform::Object ^ GetAt(unsigned int index) = Windows::Foundation::Collections::IVector<Platform::Object ^>::GetAt
{
return m_source->GetAt(index);
}
virtual bool IndexOf(Platform::Object ^ item, unsigned int* index) = Windows::Foundation::Collections::IVector<Platform::Object ^>::IndexOf
{
return m_source->IndexOf(item, index);
}
property unsigned int Size
{
virtual unsigned int get() = Windows::Foundation::Collections::IVector<Platform::Object ^>::Size::get
{
return m_source->Size;
}
}
// IObservableVector<Object^>
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ VectorChanged
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object^>^ handler) = Windows::Foundation::Collections::IObservableVector<Platform::Object^>::VectorChanged::add
{
return m_vectorChanged += handler;
}
virtual void remove(Windows::Foundation::EventRegistrationToken token) = Windows::Foundation::Collections::IObservableVector<Platform::Object^>::VectorChanged::remove
{
m_vectorChanged -= token;
}
}
// IIterable<Object^>
// Not implemented
virtual Windows::Foundation::Collections::IIterator<Platform::Object^>^ First() = Windows::Foundation::Collections::IIterable<Platform::Object^>::First
{
throw ref new Platform::NotImplementedException();
}
// Event handlers
void OnSourceBindableVectorChanged(Windows::UI::Xaml::Interop::IBindableObservableVector ^ source, Platform::Object ^ e)
{
Windows::Foundation::Collections::IVectorChangedEventArgs ^ args = safe_cast<Windows::Foundation::Collections::IVectorChangedEventArgs ^>(e);
m_vectorChanged(this, args);
}
Windows::UI::Xaml::Interop::IBindableVector ^ m_source;
int m_currentPosition;
event Windows::Foundation::EventHandler<Platform::Object ^> ^ m_currentChanged;
event Windows::UI::Xaml::Data::CurrentChangingEventHandler ^ m_currentChanging;
event Windows::Foundation::Collections::VectorChangedEventHandler<Platform::Object ^> ^ m_vectorChanged;
};
public
ref class AlwaysSelectedCollectionViewConverter sealed : public Windows::UI::Xaml::Data::IValueConverter
{
public:
AlwaysSelectedCollectionViewConverter()
{
}
private:
virtual Platform::Object
^ Convert(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{
auto result = dynamic_cast<Windows::UI::Xaml::Interop::IBindableVector ^>(value);
if (result)
{
return ref new AlwaysSelectedCollectionView(result);
}
return Windows::UI::Xaml::DependencyProperty::UnsetValue; // Can't convert
}
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ /*value*/,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{
return Windows::UI::Xaml::DependencyProperty::UnsetValue;
}
};
}
}

View File

@@ -1,149 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "AppLifecycleLogger.h"
#include <winmeta.h>
using namespace std;
using namespace winrt;
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::ApplicationModel::Background;
using namespace winrt::Windows::ApplicationModel::Core;
using namespace winrt::Windows::Foundation::Diagnostics;
using namespace winrt::Windows::UI::ViewManagement;
namespace CalculatorApp
{
#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
constexpr int64_t MICROSOFT_KEYWORD_RESERVED_44 = 0x0000100000000000; // Bit 44 (reserved for future assignment)
#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;
constexpr int64_t MICROSOFT_KEYWORD_RESERVED_44 = 0;
#endif
#pragma region TraceLogger setup and cleanup
AppLifecycleLogger::AppLifecycleLogger()
: m_appLifecycleProvider(
L"Microsoft.Windows.AppLifeCycle",
LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }),
GUID{ 0xef00584a, 0x2655, 0x462c, 0xbc, 0x24, 0xe7, 0xde, 0x63, 0xe, 0x7f, 0xbf }) // Unique provider ID {EF00584A-2655-462C-BC24-E7DE630E7FBF}
{
}
AppLifecycleLogger::~AppLifecycleLogger()
{
}
AppLifecycleLogger& AppLifecycleLogger::GetInstance()
{
static AppLifecycleLogger s_selfInstance;
return s_selfInstance;
}
bool AppLifecycleLogger::GetTraceLoggingProviderEnabled() const
{
return m_appLifecycleProvider.Enabled();
}
#pragma region Tracing methods
void AppLifecycleLogger::LogAppLifecycleEvent(hstring const& eventName, LoggingFields const& fields) const
{
m_appLifecycleProvider.LogEvent(
eventName, fields, LoggingLevel::Information, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_3 | WINEVENT_KEYWORD_RESPONSE_TIME));
}
#pragma endregion
void AppLifecycleLogger::LaunchUIResponsive() const
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields{};
PopulateAppInfo(fields);
LogAppLifecycleEvent(L"ModernAppLaunch_UIResponsive", fields);
}
void AppLifecycleLogger::LaunchVisibleComplete() const
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields{};
PopulateAppInfo(fields);
LogAppLifecycleEvent(L"ModernAppLaunch_VisibleComplete", fields);
}
void AppLifecycleLogger::ResumeUIResponsive() const
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields{};
PopulateAppInfo(fields);
LogAppLifecycleEvent(L"ModernAppResume_UIResponsive", fields);
}
void AppLifecycleLogger::ResumeVisibleComplete() const
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields{};
PopulateAppInfo(fields);
LogAppLifecycleEvent(L"ModernAppResume_VisibleComplete", fields);
}
void AppLifecycleLogger::ResizeUIResponsive() const
{
ResizeUIResponsive(ApplicationView::GetForCurrentView().Id());
}
void AppLifecycleLogger::ResizeUIResponsive(int32_t viewId) const
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields{};
PopulateAppInfo(fields);
fields.AddInt32(L"ViewId", viewId);
LogAppLifecycleEvent(L"ModernAppResize_UIResponsive", fields);
}
void AppLifecycleLogger::ResizeVisibleComplete() const
{
ResizeVisibleComplete(ApplicationView::GetForCurrentView().Id());
}
void AppLifecycleLogger::ResizeVisibleComplete(int32_t viewId) const
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields{};
PopulateAppInfo(fields);
fields.AddInt32(L"ViewId", viewId);
LogAppLifecycleEvent(L"ModernAppResize_VisibleComplete", fields);
}
void AppLifecycleLogger::PopulateAppInfo(LoggingFields& fields) const
{
auto appId = CoreApplication::Id();
auto aumId = Package::Current().Id().FamilyName() + L"!" + appId;
auto packageFullName = Package::Current().Id().FullName();
auto psmKey = Package::Current().Id().FullName() + L"+" + appId;
fields.AddString(L"AumId", aumId);
fields.AddString(L"PackageFullName", packageFullName);
fields.AddString(L"PsmKey", psmKey);
}
}

View File

@@ -0,0 +1,152 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using CalculatorApp.ViewModel.Common;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Core;
using Windows.Foundation.Diagnostics;
using Windows.UI.ViewManagement;
namespace CalculatorApp
{
static public partial class Globals
{
#if 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
public const long MICROSOFT_KEYWORD_LEVEL_1 = 0x0000800000000000; // Bit 47
public const long MICROSOFT_KEYWORD_LEVEL_2 = 0x0000400000000000; // Bit 46
public const long MICROSOFT_KEYWORD_LEVEL_3 = 0x0000200000000000; // Bit 45
public const long MICROSOFT_KEYWORD_RESERVED_44 = 0x0000100000000000; // Bit 44 (reserved for future assignment)
#else
// define all Keyword options as 0 when we do not want to upload app diagnostics
public const long MICROSOFT_KEYWORD_LEVEL_1 = 0;
public const long MICROSOFT_KEYWORD_LEVEL_2 = 0;
public const long MICROSOFT_KEYWORD_LEVEL_3 = 0;
public const long MICROSOFT_KEYWORD_RESERVED_44 = 0;
#endif
}
class AppLifecycleLogger
{
public static AppLifecycleLogger GetInstance()
{
return s_selfInstance.Value;
}
public bool GetTraceLoggingProviderEnabled()
{
return m_appLifecycleProvider.Enabled;
}
public void LaunchUIResponsive()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppLaunch_UIResponsive", fields);
}
public void LaunchVisibleComplete()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppLaunch_VisibleComplete", fields);
}
public void ResumeUIResponsive()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppResume_UIResponsive", fields);
}
public void ResumeVisibleComplete()
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
LogAppLifecycleEvent("ModernAppResume_VisibleComplete", fields);
}
public void ResizeUIResponsive()
{
ResizeUIResponsive(ApplicationView.GetForCurrentView().Id);
}
public void ResizeVisibleComplete()
{
ResizeVisibleComplete(ApplicationView.GetForCurrentView().Id);
}
public void ResizeUIResponsive(int viewId)
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
fields.AddInt32("ViewId", viewId);
LogAppLifecycleEvent("ModernAppResize_UIResponsive", fields);
}
public void ResizeVisibleComplete(int viewId)
{
if (!GetTraceLoggingProviderEnabled())
return;
LoggingFields fields = new LoggingFields();
PopulateAppInfo(fields);
fields.AddInt32("ViewId", viewId);
LogAppLifecycleEvent("ModernAppResize_VisibleComplete", fields);
}
// Make the object construction private to allow singleton access to this class
private AppLifecycleLogger()
{
m_appLifecycleProvider = new LoggingChannel(
"Microsoft.Windows.AppLifeCycle",
new LoggingChannelOptions(new Guid(0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba)),
new Guid(0xef00584a, 0x2655, 0x462c, 0xbc, 0x24, 0xe7, 0xde, 0x63, 0xe, 0x7f, 0xbf));
}
// Any new Log method should
// a) Decide the level of logging. This will help us in limiting recording of events only up to a certain level. See this link for guidance
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363742(v=vs.85).aspx We're using Verbose level for events that are called frequently and
// needed only for debugging or capturing perf for specific scenarios b) Should decide whether or not to log to diagnostics and pass
// TraceLoggingKeyword(MICROSOFT_KEYWORD_LEVEL_3) accordingly c) Should accept a variable number of additional data arguments if needed
private void LogAppLifecycleEvent(string eventName, LoggingFields fields)
{
m_appLifecycleProvider.LogEvent(
eventName, fields, LoggingLevel.Information, new LoggingOptions(Globals.MICROSOFT_KEYWORD_LEVEL_3 | Utilities.GetConst_WINEVENT_KEYWORD_RESPONSE_TIME()));
}
private void PopulateAppInfo(LoggingFields fields)
{
var appId = CoreApplication.Id;
var aumId = Package.Current.Id.FamilyName + "!" + appId;
var packageFullName = Package.Current.Id.FullName;
var psmKey = Package.Current.Id.FullName + "+" + appId;
fields.AddString("AumId", aumId);
fields.AddString("PackageFullName", packageFullName);
fields.AddString("PsmKey", psmKey);
}
private LoggingChannel m_appLifecycleProvider;
private static readonly Lazy<AppLifecycleLogger> s_selfInstance = new Lazy<AppLifecycleLogger>(() => new AppLifecycleLogger(), true);
}
}

View File

@@ -1,41 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
class AppLifecycleLogger
{
public:
AppLifecycleLogger(AppLifecycleLogger const&) = delete;
AppLifecycleLogger const& operator=(AppLifecycleLogger const&) = delete;
~AppLifecycleLogger();
static AppLifecycleLogger& GetInstance();
bool GetTraceLoggingProviderEnabled() const;
void LaunchUIResponsive() const;
void LaunchVisibleComplete() const;
void ResumeUIResponsive() const;
void ResumeVisibleComplete() const;
void ResizeUIResponsive() const;
void ResizeVisibleComplete() const;
void ResizeUIResponsive(int32_t viewId) const;
void ResizeVisibleComplete(int32_t viewId) const;
private:
// Make the object construction private to allow singleton access to this class
AppLifecycleLogger();
// Any new Log method should
// a) Decide the level of logging. This will help us in limiting recording of events only up to a certain level. See this link for guidance
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363742(v=vs.85).aspx We're using Verbose level for events that are called frequently and
// needed only for debugging or capturing perf for specific scenarios b) Should decide whether or not to log to diagnostics and pass
// TraceLoggingKeyword(MICROSOFT_KEYWORD_LEVEL_3) accordingly c) Should accept a variable number of additional data arguments if needed
void LogAppLifecycleEvent(winrt::hstring const& eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields const& fields) const;
void PopulateAppInfo(winrt::Windows::Foundation::Diagnostics::LoggingFields& fields) const;
winrt::Windows::Foundation::Diagnostics::LoggingChannel m_appLifecycleProvider;
};
}

View File

@@ -0,0 +1,832 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel;
using CalculatorApp.ViewModel.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using MUXC = Microsoft.UI.Xaml.Controls;
namespace CalculatorApp
{
namespace Common
{
static partial class KeyboardShortcutManagerLocals
{
// Lights up all of the buttons in the given range
// The range is defined by a pair of iterators
static public void LightUpButtons(IEnumerable<WeakReference> buttons)
{
foreach (var button in buttons)
{
var btn = button.Target as ButtonBase;
if (btn != null && btn.IsEnabled)
{
LightUpButton(btn);
}
}
}
static public void LightUpButton(ButtonBase button)
{
// If the button is a toggle button then we don't need
// to change the UI of the button
if (button is ToggleButton)
{
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
var timer = new DispatcherTimer();
TimeSpan lightUpTime = TimeSpan.FromMilliseconds(50); // 5e5 100-ns
timer.Interval = lightUpTime;
var timerWeakReference = new WeakReference(timer);
var buttonWeakReference = new WeakReference(button);
timer.Tick += (sender, args) =>
{
var btn = buttonWeakReference.Target as ButtonBase;
if (btn != null)
{
VisualStateManager.GoToState(button, "Normal", true);
}
var tmr = timerWeakReference.Target as DispatcherTimer;
if (tmr != null)
{
tmr.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
static public void RunFirstEnabledButtonCommand(IEnumerable<WeakReference> buttons)
{
foreach (var button in buttons)
{
var btn = button.Target as ButtonBase;
if (btn != null && btn.IsEnabled)
{
RunButtonCommand(btn);
break;
}
}
}
static public void RunButtonCommand(ButtonBase button)
{
if (button.IsEnabled)
{
var command = button.Command;
var parameter = button.CommandParameter;
if (command != null && command.CanExecute(parameter))
{
command.Execute(parameter);
}
var radio = (button as RadioButton);
if (radio != null)
{
radio.IsChecked = true;
return;
}
var toggle = (button as ToggleButton);
if (toggle != null)
{
toggle.IsChecked = !(toggle.IsChecked != null && toggle.IsChecked.Value);
return;
}
}
}
}
public sealed class KeyboardShortcutManager : DependencyObject
{
public KeyboardShortcutManager()
{
}
public static readonly DependencyProperty CharacterProperty =
DependencyProperty.RegisterAttached(
"Character",
typeof(string),
typeof(KeyboardShortcutManager),
new PropertyMetadata(string.Empty, (sender, args) =>
{
OnCharacterPropertyChanged(sender, (string)args.OldValue, (string)args.NewValue);
}));
public static string GetCharacter(DependencyObject target)
{
return (string)target.GetValue(CharacterProperty);
}
public static void SetCharacter(DependencyObject target, string value)
{
target.SetValue(CharacterProperty, value);
}
public static readonly DependencyProperty VirtualKeyProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKey(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyProperty);
}
public static void SetVirtualKey(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyProperty, value);
}
public static readonly DependencyProperty VirtualKeyControlChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyControlChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyControlChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyControlChordProperty);
}
public static void SetVirtualKeyControlChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyControlChordProperty, value);
}
public static readonly DependencyProperty VirtualKeyShiftChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyShiftChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyShiftChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyShiftChordProperty);
}
public static void SetVirtualKeyShiftChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyShiftChordProperty, value);
}
public static readonly DependencyProperty VirtualKeyAltChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyAltChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyAltChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyAltChordProperty);
}
public static void SetVirtualKeyAltChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyAltChordProperty, value);
}
public static readonly DependencyProperty VirtualKeyControlShiftChordProperty =
DependencyProperty.RegisterAttached(
"VirtualKey",
typeof(MyVirtualKey),
typeof(KeyboardShortcutManager),
new PropertyMetadata(default(MyVirtualKey), (sender, args) =>
{
OnVirtualKeyControlShiftChordPropertyChanged(sender, (MyVirtualKey)args.OldValue, (MyVirtualKey)args.NewValue);
}));
public static MyVirtualKey GetVirtualKeyControlShiftChord(DependencyObject target)
{
return (MyVirtualKey)target.GetValue(VirtualKeyControlShiftChordProperty);
}
public static void SetVirtualKeyControlShiftChord(DependencyObject target, MyVirtualKey value)
{
target.SetValue(VirtualKeyControlShiftChordProperty, value);
}
internal static void Initialize()
{
var coreWindow = Window.Current.CoreWindow;
coreWindow.CharacterReceived += OnCharacterReceivedHandler;
coreWindow.KeyDown += OnKeyDownHandler;
coreWindow.Dispatcher.AcceleratorKeyActivated += OnAcceleratorKeyActivated;
KeyboardShortcutManager.RegisterNewAppViewId();
}
// Sometimes, like with popups, escape is treated as special and even
// though it is handled we get it passed through to us. In those cases
// we need to be able to ignore it (looking at e->Handled isn't sufficient
// because that always returns true).
// The onlyOnce flag is used to indicate whether we should only ignore the
// next escape, or keep ignoring until you explicitly HonorEscape.
public static void IgnoreEscape(bool onlyOnce)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int viewId = Utilities.GetWindowId();
if (s_ignoreNextEscape.ContainsKey(viewId))
{
s_ignoreNextEscape[viewId] = true;
}
if (s_keepIgnoringEscape.ContainsKey(viewId))
{
s_keepIgnoringEscape[viewId] = !onlyOnce;
}
}
}
public static void HonorEscape()
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int viewId = Utilities.GetWindowId();
if (s_ignoreNextEscape.ContainsKey(viewId))
{
s_ignoreNextEscape[viewId] = false;
}
if (s_keepIgnoringEscape.ContainsKey(viewId))
{
s_keepIgnoringEscape[viewId] = false;
}
}
}
public static void HonorShortcuts(bool allow)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int viewId = Utilities.GetWindowId();
if (s_fHonorShortcuts.ContainsKey(viewId))
{
if (s_fDisableShortcuts.ContainsKey(viewId))
{
if (s_fDisableShortcuts[viewId])
{
s_fHonorShortcuts[viewId] = false;
return;
}
}
s_fHonorShortcuts[viewId] = allow;
}
}
}
public static void DisableShortcuts(bool disable)
{
int viewId = Utilities.GetWindowId();
if (s_fDisableShortcuts.ContainsKey(viewId))
{
s_fDisableShortcuts[viewId] = disable;
}
HonorShortcuts(!disable);
}
public static void UpdateDropDownState(bool isOpen)
{
int viewId = Utilities.GetWindowId();
if (s_IsDropDownOpen.ContainsKey(viewId))
{
s_IsDropDownOpen[viewId] = isOpen;
}
}
public static void RegisterNewAppViewId()
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
int appViewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (!s_characterForButtons.ContainsKey(appViewId))
{
s_characterForButtons.Add(appViewId, new SortedDictionary<char, List<WeakReference>>());
}
if (!s_virtualKey.ContainsKey(appViewId))
{
s_virtualKey.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyControlChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyControlChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyShiftChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyShiftChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyAltChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyAltChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
if (!s_VirtualKeyControlShiftChordsForButtons.ContainsKey(appViewId))
{
s_VirtualKeyControlShiftChordsForButtons.Add(appViewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
}
s_IsDropDownOpen[appViewId] = false;
s_ignoreNextEscape[appViewId] = false;
s_keepIgnoringEscape[appViewId] = false;
s_fHonorShortcuts[appViewId] = true;
s_fDisableShortcuts[appViewId] = false;
}
}
public static void OnWindowClosed(int viewId)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
s_characterForButtons.Remove(viewId);
s_virtualKey.Remove(viewId);
s_VirtualKeyControlChordsForButtons.Remove(viewId);
s_VirtualKeyShiftChordsForButtons.Remove(viewId);
s_VirtualKeyAltChordsForButtons.Remove(viewId);
s_VirtualKeyControlShiftChordsForButtons.Remove(viewId);
s_IsDropDownOpen.Remove(viewId);
s_ignoreNextEscape.Remove(viewId);
s_keepIgnoringEscape.Remove(viewId);
s_fHonorShortcuts.Remove(viewId);
s_fDisableShortcuts.Remove(viewId);
}
}
private static void OnCharacterPropertyChanged(DependencyObject target, string oldValue, string newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = (target as ButtonBase);
int viewId = Utilities.GetWindowId();
if (s_characterForButtons.TryGetValue(viewId, out var iterViewMap))
{
if (!string.IsNullOrEmpty(oldValue))
{
iterViewMap.Remove(oldValue[0]);
}
if (!string.IsNullOrEmpty(newValue))
{
if (newValue == ".")
{
char decSep = LocalizationSettings.GetInstance().GetDecimalSeparator();
Insert(iterViewMap, decSep, new WeakReference(button));
}
else
{
Insert(iterViewMap, newValue[0], new WeakReference(button));
}
}
}
else
{
s_characterForButtons.Add(viewId, new SortedDictionary<char, List<WeakReference>>());
if (newValue == ".")
{
char decSep = LocalizationSettings.GetInstance().GetDecimalSeparator();
Insert(s_characterForButtons[viewId], decSep, new WeakReference(button));
}
else
{
Insert(s_characterForButtons[viewId], newValue[0], new WeakReference(button));
}
}
}
}
private static void OnVirtualKeyPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = ((ButtonBase)target);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_virtualKey.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(button));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_virtualKey.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_virtualKey[viewId], newValue, new WeakReference(button));
}
}
}
private static void OnVirtualKeyControlChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
Control control = (target as ButtonBase);
if (control == null)
{
// Handling Ctrl+E shortcut for Date Calc, target would be NavigationView^ in that case
control = (target as MUXC.NavigationView);
}
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyControlChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(control));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyControlChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyControlChordsForButtons[viewId], newValue, new WeakReference(control));
}
}
}
private static void OnVirtualKeyShiftChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = (target as ButtonBase);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyShiftChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(button));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyShiftChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyShiftChordsForButtons[viewId], newValue, new WeakReference(button));
}
}
}
private static void OnVirtualKeyAltChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
MUXC.NavigationView navView = (target as MUXC.NavigationView);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyAltChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(navView));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyAltChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyAltChordsForButtons[viewId], newValue, new WeakReference(navView));
}
}
}
private static void OnVirtualKeyControlShiftChordPropertyChanged(DependencyObject target, MyVirtualKey oldValue, MyVirtualKey newValue)
{
// Writer lock for the static maps
lock (s_keyboardShortcutMapLockMutex)
{
var button = (target as ButtonBase);
int viewId = Utilities.GetWindowId();
// Check if the View Id has already been registered
if (s_VirtualKeyControlShiftChordsForButtons.TryGetValue(viewId, out var iterViewMap))
{
Insert(iterViewMap, newValue, new WeakReference(button));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyControlShiftChordsForButtons.Add(viewId, new SortedDictionary<MyVirtualKey, List<WeakReference>>());
Insert(s_VirtualKeyControlShiftChordsForButtons[viewId], newValue, new 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.
private static void OnCharacterReceivedHandler(CoreWindow sender, CharacterReceivedEventArgs args)
{
int viewId = Utilities.GetWindowId();
bool hit = s_fHonorShortcuts.TryGetValue(viewId, out var currentHonorShortcuts);
if (!hit || currentHonorShortcuts)
{
char character = ((char)args.KeyCode);
var buttons = EqualRange(s_characterForButtons[viewId], character);
KeyboardShortcutManagerLocals.RunFirstEnabledButtonCommand(buttons);
KeyboardShortcutManagerLocals.LightUpButtons(buttons);
}
}
private static void OnKeyDownHandler(CoreWindow sender, KeyEventArgs args)
{
if (args.Handled)
{
return;
}
var key = args.VirtualKey;
int viewId = Utilities.GetWindowId();
bool isControlKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Control) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
bool isShiftKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Shift) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
bool isAltKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Menu) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
// Handle Ctrl + E for DateCalculator
if ((key == Windows.System.VirtualKey.E) && isControlKeyPressed && !isShiftKeyPressed && !isAltKeyPressed)
{
var lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, false);
if (lookupMap == null)
{
return;
}
var buttons = EqualRange(lookupMap, (MyVirtualKey)key);
var navView = buttons.ElementAt(0).Target as MUXC.NavigationView;
var appViewModel = (navView.DataContext as ApplicationViewModel);
appViewModel.Mode = ViewMode.Date;
var categoryName = AppResourceProvider.GetInstance().GetResourceString("DateCalculationModeText");
appViewModel.CategoryName = categoryName;
var menuItems = ((ObservableCollection<object>)navView.MenuItemsSource);
var flatIndex = NavCategory.GetFlatIndex(ViewMode.Date);
navView.SelectedItem = menuItems[flatIndex];
return;
}
if (s_ignoreNextEscape.TryGetValue(viewId, out var currentIgnoreNextEscape))
{
if (currentIgnoreNextEscape && key == Windows.System.VirtualKey.Escape)
{
if (s_keepIgnoringEscape.TryGetValue(viewId, out var currentKeepIgnoringEscape))
{
if (!currentKeepIgnoringEscape)
{
HonorEscape();
}
return;
}
}
}
if (s_fHonorShortcuts.TryGetValue(viewId, out var currentHonorShortcuts))
{
if (currentHonorShortcuts)
{
var myVirtualKey = key;
var lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, isAltKeyPressed);
if (lookupMap == null)
{
return;
}
var buttons = EqualRange(lookupMap, (MyVirtualKey)myVirtualKey);
if (buttons.Count() <= 0)
{
return;
}
KeyboardShortcutManagerLocals.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
//var currentIsDropDownOpen = s_IsDropDownOpen.find(viewId);
if (!s_IsDropDownOpen.TryGetValue(viewId, out var currentIsDropDownOpen) || !currentIsDropDownOpen)
{
// Do not Light Up Buttons when Ctrl+C, Ctrl+V, Ctrl+Insert or Shift+Insert is pressed
if (!(isControlKeyPressed && (key == Windows.System.VirtualKey.C || key == Windows.System.VirtualKey.V || key == Windows.System.VirtualKey.Insert))
& !(isShiftKeyPressed && (key == Windows.System.VirtualKey.Insert)))
{
KeyboardShortcutManagerLocals.LightUpButtons(buttons);
}
}
}
}
}
private static void OnAcceleratorKeyActivated(CoreDispatcher dispatcher, AcceleratorKeyEventArgs args)
{
if (args.KeyStatus.IsKeyReleased)
{
var 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;
}
bool controlKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Control) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
// Ctrl is pressed in addition to alt, this means Alt Gr is intended. do not navigate.
if (controlKeyPressed)
{
return;
}
bool shiftKeyPressed = (Window.Current.CoreWindow.GetKeyState(Windows.System.VirtualKey.Shift) & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
var lookupMap = GetCurrentKeyDictionary(controlKeyPressed, shiftKeyPressed, altPressed);
if (lookupMap != null)
{
var listItems = EqualRange(lookupMap, (MyVirtualKey)key);
foreach (var itemRef in listItems)
{
var item = itemRef.Target as MUXC.NavigationView;
if (item != null)
{
var navView = (MUXC.NavigationView)item;
var menuItems = ((ObservableCollection<object>)navView.MenuItemsSource);
if (menuItems != null)
{
var vm = (navView.DataContext as ApplicationViewModel);
if (null != vm)
{
ViewMode toMode = NavCategory.GetViewModeForVirtualKey(((MyVirtualKey)key));
var nvi = (menuItems[NavCategory.GetFlatIndex(toMode)] as MUXC.NavigationViewItem);
if (nvi != null && nvi.IsEnabled && NavCategory.IsValidViewMode(toMode))
{
vm.Mode = toMode;
navView.SelectedItem = nvi;
}
}
}
break;
}
}
}
}
}
private static SortedDictionary<MyVirtualKey, List<WeakReference>> GetCurrentKeyDictionary(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed)
{
int viewId = Utilities.GetWindowId();
if (controlKeyPressed)
{
if (altPressed)
{
return null;
}
else
{
if (shiftKeyPressed)
{
return s_VirtualKeyControlShiftChordsForButtons[viewId];
}
else
{
return s_VirtualKeyControlChordsForButtons[viewId];
}
}
}
else
{
if (altPressed)
{
if (!shiftKeyPressed)
{
return s_VirtualKeyAltChordsForButtons[viewId];
}
else
{
return null;
}
}
else
{
if (shiftKeyPressed)
{
return s_VirtualKeyShiftChordsForButtons[viewId];
}
else
{
return s_virtualKey[viewId];
}
}
}
}
// EqualRange is a helper function to pick a range from std::multimap.
private static IEnumerable<TValue> EqualRange<TKey, TValue>(SortedDictionary<TKey, List<TValue>> source, TKey key)
{
Debug.Assert(source != null);
if (source.TryGetValue(key, out List<TValue> items))
{
return items;
}
else
{
return Enumerable.Empty<TValue>();
}
}
// Insert is a helper function to insert a pair into std::multimap.
private static void Insert<Tkey, TValue>(SortedDictionary<Tkey, List<TValue>> dest, Tkey key, TValue value)
{
if (dest.TryGetValue(key, out List<TValue> items))
{
items.Add(value);
}
else
{
items = new List<TValue> { value };
dest.Add(key, items);
}
}
private static SortedDictionary<int, SortedDictionary<char, List<WeakReference>>> s_characterForButtons = new SortedDictionary<int, SortedDictionary<char, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_virtualKey = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyControlChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyShiftChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyAltChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>> s_VirtualKeyControlShiftChordsForButtons = new SortedDictionary<int, SortedDictionary<MyVirtualKey, List<WeakReference>>>();
private static SortedDictionary<int, bool> s_IsDropDownOpen = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_ignoreNextEscape = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_keepIgnoringEscape = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_fHonorShortcuts = new SortedDictionary<int, bool>();
private static SortedDictionary<int, bool> s_fDisableShortcuts = new SortedDictionary<int, bool>();
//private static Concurrency.reader_writer_lock s_keyboardShortcutMapLock;
private static readonly object s_keyboardShortcutMapLockMutex = new object();
}
}
}

View File

@@ -1,692 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "KeyboardShortcutManager.h"
#include "CalcViewModel/Common/AppResourceProvider.h"
#include "CalcViewModel/ApplicationViewModel.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
using namespace Concurrency;
using namespace Platform;
using namespace std;
using namespace chrono;
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);
map<int, multimap<wchar_t, WeakReference>> KeyboardShortcutManager::s_characterForButtons;
map<int, multimap<MyVirtualKey, WeakReference>> KeyboardShortcutManager::s_virtualKey;
map<int, multimap<MyVirtualKey, WeakReference>> KeyboardShortcutManager::s_VirtualKeyControlChordsForButtons;
map<int, multimap<MyVirtualKey, WeakReference>> KeyboardShortcutManager::s_VirtualKeyShiftChordsForButtons;
map<int, multimap<MyVirtualKey, WeakReference>> KeyboardShortcutManager::s_VirtualKeyAltChordsForButtons;
map<int, multimap<MyVirtualKey, WeakReference>> KeyboardShortcutManager::s_VirtualKeyControlShiftChordsForButtons;
map<int, bool> KeyboardShortcutManager::s_IsDropDownOpen;
map<int, bool> KeyboardShortcutManager::s_ignoreNextEscape;
map<int, bool> KeyboardShortcutManager::s_keepIgnoringEscape;
map<int, bool> KeyboardShortcutManager::s_fHonorShortcuts;
map<int, bool> KeyboardShortcutManager::s_fDisableShortcuts;
reader_writer_lock KeyboardShortcutManager::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 != nullptr && toggle->IsChecked->Value);
return;
}
}
}
}
}
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[viewId] = true;
}
if (s_keepIgnoringEscape.find(viewId) != s_keepIgnoringEscape.end())
{
s_keepIgnoringEscape[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[viewId] = false;
}
if (s_keepIgnoringEscape.find(viewId) != s_keepIgnoringEscape.end())
{
s_keepIgnoringEscape[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(make_pair(decSep, WeakReference(button)));
}
else
{
iterViewMap->second.insert(make_pair(newValue->Data()[0], WeakReference(button)));
}
}
}
else
{
s_characterForButtons.insert(make_pair(viewId, multimap<wchar_t, WeakReference>()));
if (newValue == L".")
{
wchar_t decSep = LocalizationSettings::GetInstance().GetDecimalSeparator();
s_characterForButtons.find(viewId)->second.insert(make_pair(decSep, WeakReference(button)));
}
else
{
s_characterForButtons.find(viewId)->second.insert(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_virtualKey.find(viewId);
// Check if the View Id has already been registered
if (iterViewMap != s_virtualKey.end())
{
iterViewMap->second.insert(make_pair(newValue, WeakReference(button)));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_virtualKey.insert(make_pair(viewId, multimap<MyVirtualKey, WeakReference>()));
s_virtualKey.find(viewId)->second.insert(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(make_pair(newValue, WeakReference(control)));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyControlChordsForButtons.insert(make_pair(viewId, multimap<MyVirtualKey, WeakReference>()));
s_VirtualKeyControlChordsForButtons.find(viewId)->second.insert(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(make_pair(newValue, WeakReference(button)));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyShiftChordsForButtons.insert(make_pair(viewId, multimap<MyVirtualKey, WeakReference>()));
s_VirtualKeyShiftChordsForButtons.find(viewId)->second.insert(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(make_pair(newValue, WeakReference(navView)));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyAltChordsForButtons.insert(make_pair(viewId, multimap<MyVirtualKey, WeakReference>()));
s_VirtualKeyAltChordsForButtons.find(viewId)->second.insert(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(make_pair(newValue, WeakReference(button)));
}
else
{
// If the View Id is not already registered, then register it and make the entry
s_VirtualKeyControlShiftChordsForButtons.insert(make_pair(viewId, multimap<MyVirtualKey, WeakReference>()));
s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second.insert(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() || 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 multimap<MyVirtualKey, WeakReference>* KeyboardShortcutManager::GetCurrentKeyDictionary(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed)
{
int viewId = Utils::GetWindowId();
if (controlKeyPressed)
{
if (altPressed)
{
return nullptr;
}
else
{
if (shiftKeyPressed)
{
return &s_VirtualKeyControlShiftChordsForButtons.find(viewId)->second;
}
else
{
return &s_VirtualKeyControlChordsForButtons.find(viewId)->second;
}
}
}
else
{
if (altPressed)
{
if (!shiftKeyPressed)
{
return &s_VirtualKeyAltChordsForButtons.find(viewId)->second;
}
else
{
return nullptr;
}
}
else
{
if (shiftKeyPressed)
{
return &s_VirtualKeyShiftChordsForButtons.find(viewId)->second;
}
else
{
return &s_virtualKey.find(viewId)->second;
}
}
}
}
void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow ^ sender, KeyEventArgs ^ args)
{
if (args->Handled)
{
return;
}
auto key = args->VirtualKey;
int viewId = Utils::GetWindowId();
const bool isControlKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
const bool isShiftKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Shift) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
const bool isAltKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Menu) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
// Handle Ctrl + E for DateCalculator
if ((key == VirtualKey::E) && isControlKeyPressed && !isShiftKeyPressed && !isAltKeyPressed)
{
const auto lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, false);
if (lookupMap == nullptr)
{
return;
}
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 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;
}
}
}
auto currentHonorShortcuts = s_fHonorShortcuts.find(viewId);
if (currentHonorShortcuts != s_fHonorShortcuts.end())
{
if (currentHonorShortcuts->second)
{
const auto myVirtualKey = static_cast<MyVirtualKey>(key);
const auto lookupMap = GetCurrentKeyDictionary(isControlKeyPressed, isShiftKeyPressed, isAltKeyPressed);
if (lookupMap == nullptr)
{
return;
}
auto buttons = lookupMap->equal_range(myVirtualKey);
if (buttons.first == buttons.second)
{
return;
}
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
auto currentIsDropDownOpen = s_IsDropDownOpen.find(viewId);
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::OnAcceleratorKeyActivated(CoreDispatcher ^, AcceleratorKeyEventArgs ^ args)
{
if (args->KeyStatus.IsKeyReleased)
{
auto key = args->VirtualKey;
const 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 bool controlKeyPressed =
(Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
// Ctrl is pressed in addition to alt, this means Alt Gr is intended. do not navigate.
if (controlKeyPressed)
{
return;
}
const bool shiftKeyPressed = (Window::Current->CoreWindow->GetKeyState(VirtualKey::Shift) & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
const auto lookupMap = GetCurrentKeyDictionary(controlKeyPressed, shiftKeyPressed, altPressed);
if (lookupMap != nullptr)
{
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;
}
}
}
}
}
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->Dispatcher->AcceleratorKeyActivated +=
ref new TypedEventHandler<CoreDispatcher ^, AcceleratorKeyEventArgs ^>(&KeyboardShortcutManager::OnAcceleratorKeyActivated);
KeyboardShortcutManager::RegisterNewAppViewId();
}
void KeyboardShortcutManager::UpdateDropDownState(bool isOpen)
{
int viewId = Utils::GetWindowId();
if (s_IsDropDownOpen.find(viewId) != s_IsDropDownOpen.end())
{
s_IsDropDownOpen[viewId] = isOpen;
}
}
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())
{
if (s_fDisableShortcuts.find(viewId) != s_fDisableShortcuts.end())
{
if (s_fDisableShortcuts[viewId])
{
s_fHonorShortcuts[viewId] = false;
return;
}
}
s_fHonorShortcuts[viewId] = allow;
}
}
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(make_pair(appViewId, multimap<wchar_t, WeakReference>()));
}
if (s_virtualKey.find(appViewId) == s_virtualKey.end())
{
s_virtualKey.insert(make_pair(appViewId, multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyControlChordsForButtons.find(appViewId) == s_VirtualKeyControlChordsForButtons.end())
{
s_VirtualKeyControlChordsForButtons.insert(make_pair(appViewId, multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyShiftChordsForButtons.find(appViewId) == s_VirtualKeyShiftChordsForButtons.end())
{
s_VirtualKeyShiftChordsForButtons.insert(make_pair(appViewId, multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyAltChordsForButtons.find(appViewId) == s_VirtualKeyAltChordsForButtons.end())
{
s_VirtualKeyAltChordsForButtons.insert(make_pair(appViewId, multimap<MyVirtualKey, WeakReference>()));
}
if (s_VirtualKeyControlShiftChordsForButtons.find(appViewId) == s_VirtualKeyControlShiftChordsForButtons.end())
{
s_VirtualKeyControlShiftChordsForButtons.insert(make_pair(appViewId, multimap<MyVirtualKey, WeakReference>()));
}
s_IsDropDownOpen[appViewId] = false;
s_ignoreNextEscape[appViewId] = false;
s_keepIgnoringEscape[appViewId] = false;
s_fHonorShortcuts[appViewId] = true;
s_fDisableShortcuts[appViewId] = false;
}
void KeyboardShortcutManager::OnWindowClosed(int viewId)
{
// Writer lock for the static maps
reader_writer_lock::scoped_lock lock(s_keyboardShortcutMapLock);
s_characterForButtons.erase(viewId);
s_virtualKey.erase(viewId);
s_VirtualKeyControlChordsForButtons.erase(viewId);
s_VirtualKeyShiftChordsForButtons.erase(viewId);
s_VirtualKeyAltChordsForButtons.erase(viewId);
s_VirtualKeyControlShiftChordsForButtons.erase(viewId);
s_IsDropDownOpen.erase(viewId);
s_ignoreNextEscape.erase(viewId);
s_keepIgnoringEscape.erase(viewId);
s_fHonorShortcuts.erase(viewId);
s_fDisableShortcuts.erase(viewId);
}
void KeyboardShortcutManager::DisableShortcuts(bool disable)
{
int viewId = Utils::GetWindowId();
if (s_fDisableShortcuts.find(viewId) != s_fDisableShortcuts.end())
{
s_fDisableShortcuts[viewId] = disable;
}
HonorShortcuts(!disable);
}

View File

@@ -1,87 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
#include "CalcViewModel/Common/MyVirtualKey.h"
namespace CalculatorApp
{
namespace Common
{
public
ref class KeyboardShortcutManager sealed
{
public:
KeyboardShortcutManager()
{
}
DEPENDENCY_PROPERTY_OWNER(KeyboardShortcutManager);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(Platform::String ^, Character);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKey);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlChord);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyShiftChord);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyAltChord);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(MyVirtualKey, VirtualKeyControlShiftChord);
internal :
static void
Initialize();
// Sometimes, like with popups, escape is treated as special and even
// though it is handled we get it passed through to us. In those cases
// we need to be able to ignore it (looking at e->Handled isn't sufficient
// because that always returns true).
// The onlyOnce flag is used to indicate whether we should only ignore the
// next escape, or keep ignoring until you explicitly HonorEscape.
static void IgnoreEscape(bool onlyOnce);
static void HonorEscape();
static void HonorShortcuts(bool allow);
static void DisableShortcuts(bool disable);
static void UpdateDropDownState(bool);
static void RegisterNewAppViewId();
static void OnWindowClosed(int viewId);
private:
static void OnCharacterPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, Platform::String ^ oldValue, Platform::String ^ newValue);
static void OnVirtualKeyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue);
static void OnVirtualKeyControlChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue);
static void OnVirtualKeyShiftChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue);
static void OnVirtualKeyAltChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue);
static void
OnVirtualKeyControlShiftChordPropertyChanged(Windows::UI::Xaml::DependencyObject ^ target, MyVirtualKey oldValue, MyVirtualKey newValue);
static void OnCharacterReceivedHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::CharacterReceivedEventArgs ^ args);
static void OnKeyDownHandler(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args);
static void OnAcceleratorKeyActivated(Windows::UI::Core::CoreDispatcher ^, Windows::UI::Core::AcceleratorKeyEventArgs ^ args);
static const std::multimap<MyVirtualKey, Platform::WeakReference>*
KeyboardShortcutManager::GetCurrentKeyDictionary(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed);
private:
static std::map<int, std::multimap<wchar_t, Platform::WeakReference>> s_characterForButtons;
static std::map<int, std::multimap<MyVirtualKey, Platform::WeakReference>> s_virtualKey;
static std::map<int, std::multimap<MyVirtualKey, Platform::WeakReference>> s_VirtualKeyControlChordsForButtons;
static std::map<int, std::multimap<MyVirtualKey, Platform::WeakReference>> s_VirtualKeyShiftChordsForButtons;
static std::map<int, std::multimap<MyVirtualKey, Platform::WeakReference>> s_VirtualKeyAltChordsForButtons;
static std::map<int, std::multimap<MyVirtualKey, Platform::WeakReference>> s_VirtualKeyControlShiftChordsForButtons;
static std::map<int, bool> s_IsDropDownOpen;
static std::map<int, bool> s_ignoreNextEscape;
static std::map<int, bool> s_keepIgnoringEscape;
static std::map<int, bool> s_fHonorShortcuts;
static std::map<int, bool> s_fDisableShortcuts;
static Concurrency::reader_writer_lock s_keyboardShortcutMapLock;
};
}
}

View File

@@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace CalculatorApp
{
namespace Common
{
public sealed class ValidSelectedItemConverter : Windows.UI.Xaml.Data.IValueConverter
{
public ValidSelectedItemConverter()
{ }
public object Convert(object value, Type targetType, object parameter, string language)
{
// Pass through as we don't want to change the value from the source
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value != null)
{
return value;
}
// Stop the binding if the object is nullptr
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
}
}
public sealed class ValidSelectedIndexConverter : Windows.UI.Xaml.Data.IValueConverter
{
public ValidSelectedIndexConverter()
{ }
public object Convert(object value, Type targetType, object parameter, string language)
{
// Pass through as we don't want to change the value from the source
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
// The value to be valid has to be a boxed int32 value
// extract that value and ensure it is valid, ie >= 0
if (value != null)
{
var box = value as Windows.Foundation.IPropertyValue;
if (box != null && box.Type == Windows.Foundation.PropertyType.Int32)
{
int index = box.GetInt32();
if (index >= 0)
{
return value;
}
}
}
// The value is not valid therefore stop the binding right here
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
}
}
}
}

View File

@@ -1,92 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Common
{
public
ref class ValidSelectedItemConverter sealed : public Windows::UI::Xaml::Data::IValueConverter
{
public:
ValidSelectedItemConverter()
{
}
private:
virtual Platform::Object
^ Convert(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{
// Pass through as we don't want to change the value from the source
return value;
}
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{
if (value)
{
return value;
}
// Stop the binding if the object is nullptr
return Windows::UI::Xaml::DependencyProperty::UnsetValue;
}
};
public
ref class ValidSelectedIndexConverter sealed : public Windows::UI::Xaml::Data::IValueConverter
{
public:
ValidSelectedIndexConverter()
{
}
private:
virtual Platform::Object
^ Convert(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::Convert
{
// Pass through as we don't want to change the value from the source
return value;
}
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName /*targetType*/,
Platform::Object ^ /*parameter*/,
Platform::String ^ /*language*/) = Windows::UI::Xaml::Data::IValueConverter::ConvertBack
{
// The value to be valid has to be a boxed int32 value
// extract that value and ensure it is valid, ie >= 0
if (value)
{
auto box = dynamic_cast<Windows::Foundation::IPropertyValue ^>(value);
if (box && box->Type == Windows::Foundation::PropertyType::Int32)
{
int index = box->GetInt32();
if (index >= 0)
{
return value;
}
}
}
// The value is not valid therefore stop the binding right here
return Windows::UI::Xaml::DependencyProperty::UnsetValue;
}
};
}
}

View File

@@ -1,19 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "ViewState.h"
namespace CalculatorApp
{
namespace ViewState
{
Platform::StringReference Snap(L"Snap");
Platform::StringReference DockedView(L"DockedView");
bool IsValidViewState(Platform::String ^ viewState)
{
return viewState->Equals(ViewState::Snap) || viewState->Equals(ViewState::DockedView);
}
}
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace CalculatorApp
{
static class ViewState
{
public static readonly string Snap = "Snap";
public static readonly string DockedView = "DockedView";
public static bool IsValidViewState(string viewState)
{
return (viewState == Snap) || (viewState == DockedView);
}
}
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace ViewState
{
extern Platform::StringReference Snap;
extern Platform::StringReference DockedView;
bool IsValidViewState(Platform::String ^ viewState);
}
}

View File

@@ -1,419 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "CalculationResult.h"
#include "CalculationResultAutomationPeer.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Controls;
using namespace CalculatorApp::Common;
using namespace Platform;
using namespace Windows::Devices::Input;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace std;
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, IsActive);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, MinFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, MaxFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, DisplayMargin);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, DisplayValue);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, IsInError);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, IsOperatorCommand);
#define SCALEFACTOR 0.357143
#define SMALLHEIGHTSCALEFACTOR 0
#define HEIGHTCUTOFF 100
#define INCREMENTOFFSET 1
#define MAXFONTINCREMENT 5
#define WIDTHTOFONTSCALAR 0.0556513
#define WIDTHTOFONTOFFSET 3
#define WIDTHCUTOFF 50
#define FONTTOLERANCE 0.001
#define SCROLL_RATIO 0.7
// We need a safety margin to guarantee we correctly always show/hide ScrollLeft and ScrollRight buttons when necessary.
// In rare cases, ScrollViewer::HorizontalOffset is a little low by a few (sub)pixels when users scroll to one of the extremity
// and no events are launched when they scroll again in the same direction
#define SCROLL_BUTTONS_APPROXIMATION_RANGE 4
CalculationResult::CalculationResult()
: m_isScalingText(false)
, m_haveCalculatedMax(false)
{
}
Platform::String ^ CalculationResult::GetRawDisplayValue()
{
return LocalizationSettings::GetInstance().RemoveGroupSeparators(DisplayValue);
}
void CalculationResult::OnApplyTemplate()
{
if (m_textContainer)
{
if (m_textContainerLayoutChangedToken.Value != 0)
{
m_textContainer->LayoutUpdated -= m_textContainerLayoutChangedToken;
m_textContainerLayoutChangedToken.Value = 0;
}
if (m_textContainerSizeChangedToken.Value != 0)
{
m_textContainer->SizeChanged -= m_textContainerSizeChangedToken;
m_textContainerSizeChangedToken.Value = 0;
}
if (m_textContainerViewChangedToken.Value != 0)
{
m_textContainer->ViewChanged -= m_textContainerViewChangedToken;
m_textContainerViewChangedToken.Value = 0;
}
}
if (m_textBlock != nullptr && m_textBlockSizeChangedToken.Value != 0)
{
m_textBlock->SizeChanged -= m_textBlockSizeChangedToken;
m_textBlockSizeChangedToken.Value = 0;
}
if (m_scrollLeft != nullptr && m_scrollLeftClickToken.Value != 0)
{
m_scrollLeft->Click -= m_scrollLeftClickToken;
m_scrollLeftClickToken.Value = 0;
}
if (m_scrollRight != nullptr && m_scrollRightClickToken.Value != 0)
{
m_scrollRight->Click -= m_scrollRightClickToken;
m_scrollRightClickToken.Value = 0;
}
m_textContainer = dynamic_cast<ScrollViewer ^>(GetTemplateChild("TextContainer"));
if (m_textContainer)
{
// We want to know when the size of the container changes so
// we can rescale the textbox
m_textContainerSizeChangedToken = m_textContainer->SizeChanged += ref new SizeChangedEventHandler(this, &CalculationResult::OnTextContainerSizeChanged);
m_textContainerViewChangedToken = m_textContainer->ViewChanged +=
ref new Windows::Foundation::EventHandler<Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^>(
this, &CalculatorApp::Controls::CalculationResult::OnTextContainerOnViewChanged);
m_textContainerLayoutChangedToken = m_textContainer->LayoutUpdated +=
ref new EventHandler<Object ^>(this, &CalculationResult::OnTextContainerLayoutUpdated);
m_textContainer->ChangeView(m_textContainer->ExtentWidth - m_textContainer->ViewportWidth, nullptr, nullptr);
m_scrollLeft = dynamic_cast<HyperlinkButton ^>(GetTemplateChild("ScrollLeft"));
if (m_scrollLeft)
{
m_scrollLeftClickToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &CalculationResult::OnScrollLeftClick);
}
m_scrollRight = dynamic_cast<HyperlinkButton ^>(GetTemplateChild("ScrollRight"));
if (m_scrollRight)
{
m_scrollRightClickToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &CalculationResult::OnScrollRightClick);
}
m_textBlock = dynamic_cast<TextBlock ^>(GetTemplateChild("NormalOutput"));
if (m_textBlock)
{
m_textBlock->Visibility = ::Visibility::Visible;
m_textBlockSizeChangedToken = m_textBlock->SizeChanged += ref new SizeChangedEventHandler(this, &CalculationResult::OnTextBlockSizeChanged);
}
}
UpdateVisualState();
UpdateTextState();
}
void CalculationResult::OnTextContainerLayoutUpdated(Object ^ /*sender*/, Object ^ /*e*/)
{
if (m_isScalingText)
{
UpdateTextState();
}
}
void CalculationResult::OnTextContainerSizeChanged(Object ^ /*sender*/, SizeChangedEventArgs ^ /*e*/)
{
UpdateTextState();
}
void CalculationResult::OnIsActivePropertyChanged(bool /*oldValue*/, bool /*newValue */)
{
UpdateVisualState();
}
void CalculationResult::OnDisplayValuePropertyChanged(String ^ /*oldValue*/, String ^ /*newValue*/)
{
UpdateTextState();
}
void CalculationResult::OnMinFontSizePropertyChanged(double /*oldValue*/, double /*newValue*/)
{
UpdateTextState();
}
void CalculationResult::OnMaxFontSizePropertyChanged(double /*oldValue*/, double /*newValue*/)
{
UpdateTextState();
}
void CalculationResult::OnIsInErrorPropertyChanged(bool /*oldValue*/, bool newValue)
{
// We need to have a good template for this to work
if (m_textBlock == nullptr)
{
return;
}
if (newValue)
{
// If there's an error message we need to override the normal display font
// with the font appropriate for this language. This is because the error
// message is localized and therefore can contain characters that are not
// available in the normal font.
// We use UIText as the font type because this is the most common font type to use
m_textBlock->FontFamily = LocalizationService::GetInstance()->GetLanguageFontFamilyForType(LanguageFontType::UIText);
}
else
{
// The error result is no longer an error so we will restore the
// value to FontFamily property to the value provided in the style
// for the TextBlock in the template.
m_textBlock->ClearValue(TextBlock::FontFamilyProperty);
}
}
void CalculationResult::UpdateVisualState()
{
if (IsActive)
{
VisualStateManager::GoToState(this, "Active", true);
}
else
{
VisualStateManager::GoToState(this, "Normal", true);
}
}
void CalculationResult::UpdateTextState()
{
if ((m_textContainer == nullptr) || (m_textBlock == nullptr))
{
return;
}
auto containerSize = m_textContainer->ActualWidth;
String ^ oldText = m_textBlock->Text;
String ^ newText = DisplayValue;
// Initiate the scaling operation
// UpdateLayout will keep calling us until we make it through the below 2 if-statements
if (!m_isScalingText || oldText != newText)
{
m_textBlock->Text = newText;
m_isScalingText = true;
m_haveCalculatedMax = false;
m_textBlock->InvalidateArrange();
return;
}
if (containerSize > 0)
{
double widthDiff = abs(m_textBlock->ActualWidth - containerSize);
double fontSizeChange = INCREMENTOFFSET;
if (widthDiff > WIDTHCUTOFF)
{
fontSizeChange = min<double>(max<double>(floor(WIDTHTOFONTSCALAR * widthDiff) - WIDTHTOFONTOFFSET, INCREMENTOFFSET), MAXFONTINCREMENT);
}
if (m_textBlock->ActualWidth < containerSize && abs(m_textBlock->FontSize - MaxFontSize) > FONTTOLERANCE && !m_haveCalculatedMax)
{
ModifyFontAndMargin(m_textBlock, fontSizeChange);
m_textBlock->InvalidateArrange();
return;
}
if (fontSizeChange < 5)
{
m_haveCalculatedMax = true;
}
if (m_textBlock->ActualWidth >= containerSize && abs(m_textBlock->FontSize - MinFontSize) > FONTTOLERANCE)
{
ModifyFontAndMargin(m_textBlock, -1 * fontSizeChange);
m_textBlock->InvalidateArrange();
return;
}
assert(m_textBlock->FontSize >= MinFontSize && m_textBlock->FontSize <= MaxFontSize);
m_isScalingText = false;
if (IsOperatorCommand)
{
m_textContainer->ChangeView(0.0, nullptr, nullptr);
}
else
{
m_textContainer->ChangeView(m_textContainer->ExtentWidth - m_textContainer->ViewportWidth, nullptr, nullptr);
}
}
}
void CalculationResult::ScrollLeft()
{
if (m_textContainer == nullptr)
{
return;
}
if (m_textContainer->HorizontalOffset > 0)
{
double offset = m_textContainer->HorizontalOffset - (SCROLL_RATIO * m_textContainer->ViewportWidth);
m_textContainer->ChangeView(offset, nullptr, nullptr);
}
}
void CalculationResult::ScrollRight()
{
if (m_textContainer == nullptr)
{
return;
}
if (m_textContainer->HorizontalOffset < m_textContainer->ExtentWidth - m_textContainer->ViewportWidth)
{
double offset = m_textContainer->HorizontalOffset + (SCROLL_RATIO * m_textContainer->ViewportWidth);
m_textContainer->ChangeView(offset, nullptr, nullptr);
}
}
void CalculationResult::OnKeyDown(KeyRoutedEventArgs ^ e)
{
switch (e->Key)
{
case Windows::System::VirtualKey::Left:
this->ScrollLeft();
break;
case Windows::System::VirtualKey::Right:
this->ScrollRight();
break;
}
}
void CalculationResult::OnScrollLeftClick(Object ^ sender, RoutedEventArgs ^ /*e*/)
{
ScrollLeft();
}
void CalculationResult::OnScrollRightClick(Object ^ sender, RoutedEventArgs ^ /*e*/)
{
ScrollRight();
}
void CalculationResult::UpdateScrollButtons()
{
if (m_textContainer == nullptr)
{
return;
}
bool shouldTryFocusScrollRight = false;
if (m_scrollLeft != nullptr)
{
auto scrollLeftVisibility = m_textContainer->HorizontalOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? ::Visibility::Visible : ::Visibility::Collapsed;
if (scrollLeftVisibility == ::Visibility::Collapsed)
{
shouldTryFocusScrollRight = m_scrollLeft->Equals(FocusManager::GetFocusedElement());
}
m_scrollLeft->Visibility = scrollLeftVisibility;
}
if (m_scrollRight != nullptr)
{
auto scrollRightVisibility =
m_textContainer->HorizontalOffset + m_textContainer->ViewportWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_textContainer->ExtentWidth
? ::Visibility::Visible
: ::Visibility::Collapsed;
if (scrollRightVisibility == ::Visibility::Collapsed && m_scrollLeft != nullptr && m_scrollLeft->Visibility == ::Visibility::Visible
&& m_scrollRight->Equals(FocusManager::GetFocusedElement()))
{
// ScrollRight had the focus and will be collapsed, ScrollLeft should get the focus
m_scrollLeft->Focus(::FocusState::Programmatic);
}
m_scrollRight->Visibility = scrollRightVisibility;
if (shouldTryFocusScrollRight && scrollRightVisibility == ::Visibility::Visible)
{
m_scrollRight->Focus(::FocusState::Programmatic);
}
}
}
void CalculationResult::ModifyFontAndMargin(TextBlock ^ textBox, double fontChange)
{
double cur = textBox->FontSize;
double newFontSize = 0.0;
double scaleFactor = SCALEFACTOR;
if (m_textContainer->ActualHeight <= HEIGHTCUTOFF)
{
scaleFactor = SMALLHEIGHTSCALEFACTOR;
}
newFontSize = min(max(cur + fontChange, MinFontSize), MaxFontSize);
m_textContainer->Padding = Thickness(0, 0, 0, scaleFactor * abs(cur - newFontSize));
textBox->FontSize = newFontSize;
}
void CalculationResult::OnTapped(TappedRoutedEventArgs ^ e)
{
this->Focus(::FocusState::Programmatic);
RaiseSelectedEvent();
}
void CalculationResult::OnRightTapped(RightTappedRoutedEventArgs ^ e)
{
auto requestedElement = e->OriginalSource;
if (requestedElement->Equals(dynamic_cast<Object ^>(m_textBlock)))
{
m_textBlock->Focus(::FocusState::Programmatic);
}
else
{
this->Focus(::FocusState::Programmatic);
}
}
AutomationPeer ^ CalculationResult::OnCreateAutomationPeer()
{
return ref new CalculationResultAutomationPeer(this);
}
void CalculationResult::ProgrammaticSelect()
{
RaiseSelectedEvent();
}
void CalculationResult::RaiseSelectedEvent()
{
Selected(this);
}
void CalculationResult::OnTextContainerOnViewChanged(Object ^ /*sender*/, ScrollViewerViewChangedEventArgs ^ e)
{
UpdateScrollButtons();
}
void CalculationResult::OnTextBlockSizeChanged(Object ^ /*sender*/, SizeChangedEventArgs ^ /*e*/)
{
UpdateScrollButtons();
}

View File

@@ -0,0 +1,500 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using CalculatorApp;
using CalculatorApp.Controls;
using CalculatorApp.ViewModel.Common;
using Windows.Devices.Input;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using System.Reflection;
namespace CalculatorApp
{
namespace Controls
{
public delegate void SelectedEventHandler(object sender);
public sealed class CalculationResult : Windows.UI.Xaml.Controls.Control
{
public CalculationResult()
{
m_isScalingText = false;
m_haveCalculatedMax = false;
}
public double MinFontSize
{
get { return (double)GetValue(MinFontSizeProperty); }
set { SetValue(MinFontSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for MinFontSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinFontSizeProperty =
DependencyProperty.Register(nameof(MinFontSize), typeof(double), typeof(CalculationResult), new PropertyMetadata(0.0, new PropertyChangedCallback((sender, args) =>
{
var self = (CalculationResult)sender;
self.OnMinFontSizePropertyChanged((double)args.OldValue, (double)args.NewValue);
})));
public double MaxFontSize
{
get { return (double)GetValue(MaxFontSizeProperty); }
set { SetValue(MaxFontSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for MaxFontSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MaxFontSizeProperty =
DependencyProperty.Register(nameof(MaxFontSize), typeof(double), typeof(CalculationResult), new PropertyMetadata(30.0, new PropertyChangedCallback((sender, args) =>
{
var self = (CalculationResult)sender;
self.OnMaxFontSizePropertyChanged((double)args.OldValue, (double)args.NewValue);
})));
public Thickness DisplayMargin
{
get { return (Thickness)GetValue(DisplayMarginProperty); }
set { SetValue(DisplayMarginProperty, value); }
}
// Using a DependencyProperty as the backing store for DisplayMargin. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DisplayMarginProperty =
DependencyProperty.Register(nameof(DisplayMargin), typeof(Thickness), typeof(CalculationResult), new PropertyMetadata(default(Thickness)));
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
// Using a DependencyProperty as the backing store for IsActive. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register(nameof(IsActive), typeof(bool), typeof(CalculationResult), new PropertyMetadata(default(bool), new PropertyChangedCallback((sender, args) =>
{
var self = (CalculationResult)sender;
self.OnIsActivePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
})));
public string DisplayValue
{
get { return (string)GetValue(DisplayValueProperty); }
set { SetValue(DisplayValueProperty, value); }
}
// Using a DependencyProperty as the backing store for DisplayValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DisplayValueProperty =
DependencyProperty.Register(nameof(DisplayValue), typeof(string), typeof(CalculationResult), new PropertyMetadata(string.Empty, new PropertyChangedCallback((sender, args) =>
{
var self = (CalculationResult)sender;
self.OnDisplayValuePropertyChanged((string)args.OldValue, (string)args.NewValue);
})));
public bool IsInError
{
get { return (bool)GetValue(IsInErrorProperty); }
set { SetValue(IsInErrorProperty, value); }
}
// Using a DependencyProperty as the backing store for IsInError. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsInErrorProperty =
DependencyProperty.Register(nameof(IsInError), typeof(bool), typeof(CalculationResult), new PropertyMetadata(default(bool), new PropertyChangedCallback((sender, args) =>
{
var self = (CalculationResult)sender;
self.OnIsInErrorPropertyChanged((bool)args.OldValue, (bool)args.NewValue);
})));
public bool IsOperatorCommand
{
get { return (bool)GetValue(IsOperatorCommandProperty); }
set { SetValue(IsOperatorCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for IsOperatorCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsOperatorCommandProperty =
DependencyProperty.Register(nameof(IsOperatorCommand), typeof(bool), typeof(CalculationResult), new PropertyMetadata(false));
public event SelectedEventHandler Selected;
public void ProgrammaticSelect()
{
RaiseSelectedEvent();
}
internal void UpdateTextState()
{
if ((m_textContainer == null) || (m_textBlock == null))
{
return;
}
var containerSize = m_textContainer.ActualWidth;
string oldText = m_textBlock.Text;
string newText = DisplayValue;
// Initiate the scaling operation
// UpdateLayout will keep calling us until we make it through the below 2 if-statements
if (!m_isScalingText || oldText != newText)
{
m_textBlock.Text = newText;
m_isScalingText = true;
m_haveCalculatedMax = false;
m_textBlock.InvalidateArrange();
return;
}
if (containerSize > 0)
{
double widthDiff = Math.Abs(m_textBlock.ActualWidth - containerSize);
double fontSizeChange = INCREMENTOFFSET;
if (widthDiff > WIDTHCUTOFF)
{
fontSizeChange = Math.Min((double)Math.Max((double)Math.Floor(WIDTHTOFONTSCALAR * widthDiff) - WIDTHTOFONTOFFSET, INCREMENTOFFSET), MAXFONTINCREMENT);
}
if (m_textBlock.ActualWidth < containerSize && Math.Abs(m_textBlock.FontSize - MaxFontSize) > FONTTOLERANCE && !m_haveCalculatedMax)
{
ModifyFontAndMargin(m_textBlock, fontSizeChange);
m_textBlock.InvalidateArrange();
return;
}
if (fontSizeChange < 5)
{
m_haveCalculatedMax = true;
}
if (m_textBlock.ActualWidth >= containerSize && Math.Abs(m_textBlock.FontSize - MinFontSize) > FONTTOLERANCE)
{
ModifyFontAndMargin(m_textBlock, -1 * fontSizeChange);
m_textBlock.InvalidateArrange();
return;
}
Debug.Assert(m_textBlock.FontSize >= MinFontSize && m_textBlock.FontSize <= MaxFontSize);
m_isScalingText = false;
if (IsOperatorCommand)
{
m_textContainer.ChangeView(0.0, null, null);
}
else
{
m_textContainer.ChangeView(m_textContainer.ExtentWidth - m_textContainer.ViewportWidth, null, null);
}
}
}
public string GetRawDisplayValue()
{
return LocalizationSettings.GetInstance().RemoveGroupSeparators(DisplayValue);
}
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
switch (e.Key)
{
case Windows.System.VirtualKey.Left:
this.ScrollLeft();
break;
case Windows.System.VirtualKey.Right:
this.ScrollRight();
break;
}
}
protected override void OnApplyTemplate()
{
if (m_textContainer != null)
{
m_textContainer.LayoutUpdated -= OnTextContainerLayoutUpdated;
m_textContainer.SizeChanged -= OnTextContainerSizeChanged;
m_textContainer.ViewChanged -= OnTextContainerOnViewChanged;
}
if (m_textBlock != null)
{
m_textBlock.SizeChanged -= OnTextBlockSizeChanged;
}
if (m_scrollLeft != null)
{
m_scrollLeft.Click -= OnScrollLeftClick;
}
if (m_scrollRight != null)
{
m_scrollRight.Click -= OnScrollRightClick;
}
m_textContainer = GetTemplateChild("TextContainer") as ScrollViewer;
if (m_textContainer != null)
{
// We want to know when the size of the container changes so
// we can rescale the textbox
m_textContainer.SizeChanged += OnTextContainerSizeChanged;
m_textContainer.ViewChanged += OnTextContainerOnViewChanged;
m_textContainer.LayoutUpdated += OnTextContainerLayoutUpdated;
m_textContainer.ChangeView(m_textContainer.ExtentWidth - m_textContainer.ViewportWidth, null, null);
m_scrollLeft = GetTemplateChild("ScrollLeft") as HyperlinkButton;
if (m_scrollLeft != null)
{
m_scrollLeft.Click += OnScrollLeftClick;
}
m_scrollRight = GetTemplateChild("ScrollRight") as HyperlinkButton;
if (m_scrollRight != null)
{
m_scrollRight.Click += OnScrollRightClick;
}
m_textBlock = GetTemplateChild("NormalOutput") as TextBlock;
if (m_textBlock != null)
{
m_textBlock.Visibility = Visibility.Visible;
m_textBlock.SizeChanged += OnTextBlockSizeChanged;
}
}
UpdateVisualState();
UpdateTextState();
}
protected override void OnTapped(TappedRoutedEventArgs e)
{
this.Focus(FocusState.Programmatic);
RaiseSelectedEvent();
}
protected override void OnRightTapped(RightTappedRoutedEventArgs e)
{
var requestedElement = e.OriginalSource;
if (requestedElement.Equals(m_textBlock as object))
{
m_textBlock.Focus(FocusState.Programmatic);
}
else
{
this.Focus(FocusState.Programmatic);
}
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new CalculationResultAutomationPeer(this);
}
private void OnIsActivePropertyChanged(bool oldValue, bool newValue)
{
UpdateVisualState();
}
private void OnDisplayValuePropertyChanged(string oldValue, string newValue)
{
UpdateTextState();
}
private void OnIsInErrorPropertyChanged(bool oldValue, bool newValue)
{
// We need to have a good template for this to work
if (m_textBlock == null)
{
return;
}
if (newValue)
{
// If there's an error message we need to override the normal display font
// with the font appropriate for this language. This is because the error
// message is localized and therefore can contain characters that are not
// available in the normal font.
// We use UIText as the font type because this is the most common font type to use
m_textBlock.FontFamily = LocalizationService.GetInstance().GetLanguageFontFamilyForType(LanguageFontType.UIText);
}
else
{
// The error result is no longer an error so we will restore the
// value to FontFamily property to the value provided in the style
// for the TextBlock in the template.
m_textBlock.ClearValue(TextBlock.FontFamilyProperty);
}
}
private void OnMinFontSizePropertyChanged(double oldValue, double newValue)
{
UpdateTextState();
}
private void OnMaxFontSizePropertyChanged(double oldValue, double newValue)
{
UpdateTextState();
}
private void OnTextContainerSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateTextState();
}
private void OnTextBlockSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateScrollButtons();
}
private void OnTextContainerLayoutUpdated(object sender, object e)
{
if (m_isScalingText)
{
UpdateTextState();
}
}
private void OnTextContainerOnViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
UpdateScrollButtons();
}
private void UpdateVisualState()
{
if (IsActive)
{
VisualStateManager.GoToState(this, "Active", true);
}
else
{
VisualStateManager.GoToState(this, "Normal", true);
}
}
private void OnScrollLeftClick(object sender, RoutedEventArgs e)
{
ScrollLeft();
}
private void OnScrollRightClick(object sender, RoutedEventArgs e)
{
ScrollRight();
}
private void ModifyFontAndMargin(TextBlock textBox, double fontChange)
{
double cur = textBox.FontSize;
double newFontSize = 0.0;
double scaleFactor = SCALEFACTOR;
if (m_textContainer.ActualHeight <= HEIGHTCUTOFF)
{
scaleFactor = SMALLHEIGHTSCALEFACTOR;
}
newFontSize = Math.Min(Math.Max(cur + fontChange, MinFontSize), MaxFontSize);
m_textContainer.Padding = new Thickness(0, 0, 0, scaleFactor * Math.Abs(cur - newFontSize));
textBox.FontSize = newFontSize;
}
private void UpdateScrollButtons()
{
if (m_textContainer == null)
{
return;
}
bool shouldTryFocusScrollRight = false;
if (m_scrollLeft != null)
{
var scrollLeftVisibility = m_textContainer.HorizontalOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? Visibility.Visible : Visibility.Collapsed;
if (scrollLeftVisibility == Visibility.Collapsed)
{
shouldTryFocusScrollRight = m_scrollLeft.Equals(FocusManager.GetFocusedElement());
}
m_scrollLeft.Visibility = scrollLeftVisibility;
}
if (m_scrollRight != null)
{
var scrollRightVisibility =
m_textContainer.HorizontalOffset + m_textContainer.ViewportWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_textContainer.ExtentWidth
? Visibility.Visible
: Visibility.Collapsed;
if (scrollRightVisibility == Visibility.Collapsed && m_scrollLeft != null && m_scrollLeft.Visibility == Visibility.Visible
&& m_scrollRight.Equals(FocusManager.GetFocusedElement()))
{
// ScrollRight had the focus and will be collapsed, ScrollLeft should get the focus
m_scrollLeft.Focus(FocusState.Programmatic);
}
m_scrollRight.Visibility = scrollRightVisibility;
if (shouldTryFocusScrollRight && scrollRightVisibility == Visibility.Visible)
{
m_scrollRight.Focus(FocusState.Programmatic);
}
}
}
private void ScrollLeft()
{
if (m_textContainer == null)
{
return;
}
if (m_textContainer.HorizontalOffset > 0)
{
double offset = m_textContainer.HorizontalOffset - (SCROLL_RATIO * m_textContainer.ViewportWidth);
m_textContainer.ChangeView(offset, null, null);
}
}
private void ScrollRight()
{
if (m_textContainer == null)
{
return;
}
if (m_textContainer.HorizontalOffset < m_textContainer.ExtentWidth - m_textContainer.ViewportWidth)
{
double offset = m_textContainer.HorizontalOffset + (SCROLL_RATIO * m_textContainer.ViewportWidth);
m_textContainer.ChangeView(offset, null, null);
}
}
private void RaiseSelectedEvent()
{
Selected?.Invoke(this);
}
private const double SCALEFACTOR = 0.357143;
private const double SMALLHEIGHTSCALEFACTOR = 0;
private const double HEIGHTCUTOFF = 100;
private const double INCREMENTOFFSET = 1;
private const double MAXFONTINCREMENT = 5;
private const double WIDTHTOFONTSCALAR = 0.0556513;
private const double WIDTHTOFONTOFFSET = 3;
private const double WIDTHCUTOFF = 50;
private const double FONTTOLERANCE = 0.001;
private const double SCROLL_RATIO = 0.7;
// We need a safety margin to guarantee we correctly always show/hide ScrollLeft and ScrollRight buttons when necessary.
// In rare cases, ScrollViewer::HorizontalOffset is a little low by a few (sub)pixels when users scroll to one of the extremity
// and no events are launched when they scroll again in the same direction
private const double SCROLL_BUTTONS_APPROXIMATION_RANGE = 4;
private Windows.UI.Xaml.Controls.ScrollViewer m_textContainer;
private Windows.UI.Xaml.Controls.TextBlock m_textBlock;
private Windows.UI.Xaml.Controls.HyperlinkButton m_scrollLeft;
private Windows.UI.Xaml.Controls.HyperlinkButton m_scrollRight;
private bool m_isScalingText;
private bool m_haveCalculatedMax;
}
}
}

View File

@@ -1,81 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
delegate void SelectedEventHandler(Platform::Object ^ sender);
public
ref class CalculationResult sealed : public Windows::UI::Xaml::Controls::Control
{
public:
CalculationResult();
DEPENDENCY_PROPERTY_OWNER(CalculationResult);
DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, MinFontSize, 0.0);
DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, MaxFontSize, 30.0);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Thickness, DisplayMargin);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, IsActive);
DEPENDENCY_PROPERTY_WITH_CALLBACK(Platform::String ^, DisplayValue);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, IsInError);
DEPENDENCY_PROPERTY_WITH_DEFAULT(bool, IsOperatorCommand, false);
event SelectedEventHandler ^ Selected;
void ProgrammaticSelect();
internal : void UpdateTextState();
Platform::String ^ GetRawDisplayValue();
protected:
virtual void OnKeyDown(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
virtual void OnApplyTemplate() override;
virtual void OnTapped(Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) override;
virtual void OnRightTapped(Windows::UI::Xaml::Input::RightTappedRoutedEventArgs ^ e) override;
virtual Windows::UI::Xaml::Automation::Peers::AutomationPeer ^ OnCreateAutomationPeer() override;
private:
void OnIsActivePropertyChanged(bool oldValue, bool newValue);
void OnDisplayValuePropertyChanged(Platform::String ^ oldValue, Platform::String ^ newValue);
void OnIsInErrorPropertyChanged(bool oldValue, bool newValue);
void OnMinFontSizePropertyChanged(double oldValue, double newValue);
void OnMaxFontSizePropertyChanged(double oldValue, double newValue);
void OnTextContainerSizeChanged(Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
void OnTextBlockSizeChanged(Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
void OnTextContainerLayoutUpdated(Object ^ sender, Object ^ e);
void OnTextContainerOnViewChanged(Object ^ sender, Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^ e);
void UpdateVisualState();
void UpdateAllState();
void OnScrollLeftClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnScrollRightClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnPointerEntered(Platform::Object ^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
void OnPointerExited(Platform::Object ^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
void ModifyFontAndMargin(Windows::UI::Xaml::Controls::TextBlock ^ textBlock, double fontChange);
void UpdateScrollButtons();
void ScrollLeft();
void ScrollRight();
void RaiseSelectedEvent();
Windows::UI::Xaml::Controls::ScrollViewer ^ m_textContainer;
Windows::UI::Xaml::Controls::TextBlock ^ m_textBlock;
Windows::UI::Xaml::Controls::HyperlinkButton ^ m_scrollLeft;
Windows::UI::Xaml::Controls::HyperlinkButton ^ m_scrollRight;
bool m_isScalingText;
bool m_haveCalculatedMax;
Windows::Foundation::EventRegistrationToken m_textContainerLayoutChangedToken;
Windows::Foundation::EventRegistrationToken m_textContainerViewChangedToken;
Windows::Foundation::EventRegistrationToken m_textContainerSizeChangedToken;
Windows::Foundation::EventRegistrationToken m_scrollRightClickToken;
Windows::Foundation::EventRegistrationToken m_scrollLeftClickToken;
Windows::Foundation::EventRegistrationToken m_textBlockSizeChangedToken;
};
}
}

View File

@@ -1,37 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "CalculationResultAutomationPeer.h"
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Automation::Peers;
namespace CalculatorApp::Controls
{
CalculationResultAutomationPeer::CalculationResultAutomationPeer(FrameworkElement ^ owner)
: FrameworkElementAutomationPeer(owner)
{
}
AutomationControlType CalculationResultAutomationPeer::GetAutomationControlTypeCore()
{
return AutomationControlType::Text;
}
Platform::Object ^ CalculationResultAutomationPeer::GetPatternCore(PatternInterface pattern)
{
if (pattern == PatternInterface::Invoke)
{
return this;
}
return FrameworkElementAutomationPeer::GetPatternCore(pattern);
}
void CalculationResultAutomationPeer::Invoke()
{
auto owner = static_cast<CalculationResult ^>(this->Owner);
owner->ProgrammaticSelect();
}
}

View File

@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
namespace CalculatorApp
{
namespace Controls
{
public sealed class CalculationResultAutomationPeer : Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer,
Windows.UI.Xaml.Automation.Provider.IInvokeProvider
{
public CalculationResultAutomationPeer(FrameworkElement owner) : base(owner)
{
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Text;
}
protected override object GetPatternCore(PatternInterface pattern)
{
if (pattern == PatternInterface.Invoke)
{
return this;
}
return base.GetPatternCore(pattern);
}
public void Invoke()
{
var owner = (CalculationResult)this.Owner;
owner.ProgrammaticSelect();
}
}
}
}

View File

@@ -1,24 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Controls/CalculationResult.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class CalculationResultAutomationPeer sealed : Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer,
Windows::UI::Xaml::Automation::Provider::IInvokeProvider
{
public:
CalculationResultAutomationPeer(Windows::UI::Xaml::FrameworkElement ^ owner);
virtual Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() override;
virtual Platform::Object ^ GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface pattern) override;
virtual void Invoke();
};
}
}

View File

@@ -1,64 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "CalculatorButton.h"
#include "CalcViewModel/Common/CalculatorButtonPressedEventArgs.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace Windows::System;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Data;
using namespace Platform;
using namespace Windows::Foundation::Collections;
DEPENDENCY_PROPERTY_INITIALIZATION(CalculatorButton, ButtonId);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculatorButton, AuditoryFeedback);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculatorButton, HoverBackground);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculatorButton, HoverForeground);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculatorButton, PressBackground);
DEPENDENCY_PROPERTY_INITIALIZATION(CalculatorButton, PressForeground);
CalculatorButton::CalculatorButton()
{
// Set the default bindings for this button, these can be overwritten by Xaml if needed
// These are a replacement for binding in styles
Binding ^ commandBinding = ref new Binding();
commandBinding->Path = ref new PropertyPath("ButtonPressed");
this->SetBinding(Button::CommandProperty, commandBinding);
}
void CalculatorButton::OnKeyDown(KeyRoutedEventArgs ^ e)
{
// Ignore the Enter key
if (e->Key == VirtualKey::Enter)
{
return;
}
Button::OnKeyDown(e);
}
void CalculatorButton::OnKeyUp(KeyRoutedEventArgs ^ e)
{
// Ignore the Enter key
if (e->Key == VirtualKey::Enter)
{
return;
}
Button::OnKeyUp(e);
}
void CalculatorButton::OnButtonIdPropertyChanged(NumbersAndOperatorsEnum /*oldValue*/, NumbersAndOperatorsEnum newValue)
{
this->CommandParameter = ref new CalculatorButtonPressedEventArgs(AuditoryFeedback, newValue);
}
void CalculatorButton::OnAuditoryFeedbackPropertyChanged(String ^ /*oldValue*/, String ^ newValue)
{
this->CommandParameter = ref new CalculatorButtonPressedEventArgs(newValue, ButtonId);
}

View File

@@ -0,0 +1,134 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using CalculatorApp;
using CalculatorApp.Controls;
using CalculatorApp.ViewModel.Common;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Data;
using Windows.Foundation.Collections;
using Windows.Storage.Pickers;
namespace CalculatorApp
{
namespace Controls
{
public sealed class CalculatorButton : Windows.UI.Xaml.Controls.Button
{
public CalculatorButton()
{
// Set the default bindings for this button, these can be overwritten by Xaml if needed
// These are a replacement for binding in styles
Binding commandBinding = new Binding();
commandBinding.Path = new PropertyPath("ButtonPressed");
this.SetBinding(CommandProperty, commandBinding);
}
public NumbersAndOperatorsEnum ButtonId
{
get { return (NumbersAndOperatorsEnum)GetValue(ButtonIdProperty); }
set { SetValue(ButtonIdProperty, value); }
}
// Using a DependencyProperty as the backing store for ButtonId. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ButtonIdProperty =
DependencyProperty.Register(nameof(ButtonId), typeof(NumbersAndOperatorsEnum), typeof(CalculatorButton), new PropertyMetadata(default(NumbersAndOperatorsEnum), new PropertyChangedCallback((sender, args) =>
{
var self = (CalculatorButton)sender;
self.OnButtonIdPropertyChanged((NumbersAndOperatorsEnum)args.OldValue, (NumbersAndOperatorsEnum)args.NewValue);
})));
public string AuditoryFeedback
{
get { return (string)GetValue(AuditoryFeedbackProperty); }
set { SetValue(AuditoryFeedbackProperty, value); }
}
// Using a DependencyProperty as the backing store for AuditoryFeedback. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AuditoryFeedbackProperty =
DependencyProperty.Register(nameof(AuditoryFeedback), typeof(string), typeof(CalculatorButton), new PropertyMetadata(string.Empty, new PropertyChangedCallback((sender, args) =>
{
var self = (CalculatorButton)sender;
self.OnAuditoryFeedbackPropertyChanged((string)args.OldValue, (string)args.NewValue);
})));
public Windows.UI.Xaml.Media.Brush HoverBackground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(HoverBackgroundProperty); }
set { SetValue(HoverBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverBackgroundProperty =
DependencyProperty.Register(nameof(HoverBackground), typeof(Windows.UI.Xaml.Media.Brush), typeof(CalculatorButton), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush HoverForeground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(HoverForegroundProperty); }
set { SetValue(HoverForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverForegroundProperty =
DependencyProperty.Register(nameof(HoverForeground), typeof(Windows.UI.Xaml.Media.Brush), typeof(CalculatorButton), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush PressBackground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(PressBackgroundProperty); }
set { SetValue(PressBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for PressBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressBackgroundProperty =
DependencyProperty.Register(nameof(PressBackground), typeof(Windows.UI.Xaml.Media.Brush), typeof(CalculatorButton), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush PressForeground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(PressForegroundProperty); }
set { SetValue(PressForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for PressForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressForegroundProperty =
DependencyProperty.Register(nameof(PressForeground), typeof(Windows.UI.Xaml.Media.Brush), typeof(CalculatorButton), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
// Ignore the Enter key
if (e.Key == VirtualKey.Enter)
{
return;
}
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyRoutedEventArgs e)
{
// Ignore the Enter key
if (e.Key == VirtualKey.Enter)
{
return;
}
base.OnKeyUp(e);
}
private void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue)
{
this.CommandParameter = new CalculatorButtonPressedEventArgs(AuditoryFeedback, newValue);
}
private void OnAuditoryFeedbackPropertyChanged(string oldValue, string newValue)
{
this.CommandParameter = new CalculatorButtonPressedEventArgs(newValue, ButtonId);
}
}
}
}

View File

@@ -1,36 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
#include "CalcViewModel/Common/CalculatorButtonUser.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class CalculatorButton sealed : Windows::UI::Xaml::Controls::Button
{
public:
CalculatorButton();
DEPENDENCY_PROPERTY_OWNER(CalculatorButton);
DEPENDENCY_PROPERTY_WITH_CALLBACK(NumbersAndOperatorsEnum, ButtonId);
DEPENDENCY_PROPERTY_WITH_CALLBACK(Platform::String ^, AuditoryFeedback);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, HoverBackground);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, HoverForeground);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, PressBackground);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, PressForeground);
protected:
virtual void OnKeyDown(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
virtual void OnKeyUp(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
private:
void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue);
void OnAuditoryFeedbackPropertyChanged(Platform::String ^ oldValue, Platform::String ^ newValue);
};
}
}

View File

@@ -1,507 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "CalcViewModel/Common/AppResourceProvider.h"
#include "CalcViewModel/Common/LocalizationStringUtil.h"
#include "EquationTextBox.h"
using namespace std;
using namespace Platform;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::ApplicationModel;
using namespace Windows::UI::Text;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Media;
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationColor);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationButtonForegroundColor);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, ColorChooserFlyout);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationButtonContentIndex);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, HasError);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, IsAddEquationMode);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, MathEquation);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, ErrorText);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, IsEquationLineDisabled);
EquationTextBox::EquationTextBox()
{
}
void EquationTextBox::OnApplyTemplate()
{
m_equationButton = dynamic_cast<ToggleButton ^>(GetTemplateChild("EquationButton"));
m_richEditBox = dynamic_cast<MathRichEditBox ^>(GetTemplateChild("MathRichEditBox"));
m_deleteButton = dynamic_cast<Button ^>(GetTemplateChild("DeleteButton"));
m_removeButton = dynamic_cast<Button ^>(GetTemplateChild("RemoveButton"));
m_functionButton = dynamic_cast<Button ^>(GetTemplateChild("FunctionButton"));
m_colorChooserButton = dynamic_cast<ToggleButton ^>(GetTemplateChild("ColorChooserButton"));
m_richEditContextMenu = dynamic_cast<MenuFlyout ^>(GetTemplateChild("MathRichEditContextMenu"));
m_kgfEquationMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("FunctionAnalysisMenuItem"));
m_removeMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("RemoveFunctionMenuItem"));
m_colorChooserMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("ChangeFunctionStyleMenuItem"));
m_cutMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("CutMenuItem"));
m_copyMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("CopyMenuItem"));
m_pasteMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("PasteMenuItem"));
m_undoMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("UndoMenuItem"));
m_selectAllMenuItem = dynamic_cast<MenuFlyoutItem ^>(GetTemplateChild("SelectAllMenuItem"));
auto resProvider = AppResourceProvider::GetInstance();
if (m_richEditBox != nullptr)
{
m_richEditBox->GotFocus += ref new RoutedEventHandler(this, &EquationTextBox::OnRichEditBoxGotFocus);
m_richEditBox->LostFocus += ref new RoutedEventHandler(this, &EquationTextBox::OnRichEditBoxLostFocus);
m_richEditBox->TextChanged += ref new RoutedEventHandler(this, &EquationTextBox::OnRichEditTextChanged);
m_richEditBox->SelectionFlyout = nullptr;
m_richEditBox->EquationSubmitted += ref new EventHandler<MathRichEditBoxSubmission ^>(this, &EquationTextBox::OnEquationSubmitted);
m_richEditBox->FormatRequest += ref new EventHandler<MathRichEditBoxFormatRequest ^>(this, &EquationTextBox::OnEquationFormatRequested);
}
if (m_equationButton != nullptr)
{
m_equationButton->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnEquationButtonClicked);
}
if (m_richEditContextMenu != nullptr)
{
m_richEditContextMenu->Opened += ref new EventHandler<Platform::Object ^>(this, &EquationTextBox::OnRichEditMenuOpened);
}
if (m_deleteButton != nullptr)
{
m_deleteButton->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnDeleteButtonClicked);
}
if (m_removeButton != nullptr)
{
m_removeButton->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnRemoveButtonClicked);
}
if (m_removeMenuItem != nullptr)
{
m_removeMenuItem->Text = resProvider->GetResourceString(L"removeMenuItem");
m_removeMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnRemoveButtonClicked);
}
if (m_colorChooserButton != nullptr)
{
m_colorChooserButton->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnColorChooserButtonClicked);
}
if (m_colorChooserMenuItem != nullptr)
{
m_colorChooserMenuItem->Text = resProvider->GetResourceString(L"colorChooserMenuItem");
m_colorChooserMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnColorChooserButtonClicked);
}
if (m_functionButton != nullptr)
{
m_functionButton->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnFunctionButtonClicked);
m_functionButton->IsEnabled = false;
}
if (m_kgfEquationMenuItem != nullptr)
{
m_kgfEquationMenuItem->Text = resProvider->GetResourceString(L"functionAnalysisMenuItem");
m_kgfEquationMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnFunctionMenuButtonClicked);
}
if (ColorChooserFlyout != nullptr)
{
ColorChooserFlyout->Opened += ref new EventHandler<Object ^>(this, &EquationTextBox::OnColorFlyoutOpened);
ColorChooserFlyout->Closed += ref new EventHandler<Object ^>(this, &EquationTextBox::OnColorFlyoutClosed);
}
if (m_cutMenuItem != nullptr)
{
m_cutMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnCutClicked);
}
if (m_copyMenuItem != nullptr)
{
m_copyMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnCopyClicked);
}
if (m_pasteMenuItem != nullptr)
{
m_pasteMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnPasteClicked);
}
if (m_undoMenuItem != nullptr)
{
m_undoMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnUndoClicked);
}
if (m_selectAllMenuItem != nullptr)
{
m_selectAllMenuItem->Click += ref new RoutedEventHandler(this, &EquationTextBox::OnSelectAllClicked);
}
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
void EquationTextBox::OnPointerEntered(PointerRoutedEventArgs ^ e)
{
m_isPointerOver = true;
UpdateCommonVisualState();
}
void EquationTextBox::OnPointerExited(PointerRoutedEventArgs ^ e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
void EquationTextBox::OnPointerCanceled(PointerRoutedEventArgs ^ e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
void EquationTextBox::OnPointerCaptureLost(PointerRoutedEventArgs ^ e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
void EquationTextBox::OnColorFlyoutOpened(Object ^ sender, Object ^ e)
{
m_isColorChooserFlyoutOpen = true;
UpdateCommonVisualState();
}
void EquationTextBox::OnColorFlyoutClosed(Object ^ sender, Object ^ e)
{
m_colorChooserButton->IsChecked = false;
m_isColorChooserFlyoutOpen = false;
UpdateCommonVisualState();
}
void EquationTextBox::OnRichEditTextChanged(Object ^ sender, RoutedEventArgs ^ e)
{
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
void EquationTextBox::OnRichEditBoxGotFocus(Object ^ sender, RoutedEventArgs ^ e)
{
m_HasFocus = true;
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
void EquationTextBox::OnRichEditBoxLostFocus(Object ^ sender, RoutedEventArgs ^ e)
{
if (!m_richEditBox->ContextFlyout->IsOpen)
{
m_HasFocus = false;
}
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
void EquationTextBox::OnDeleteButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->SetText(::TextSetOptions::None, "");
if (m_functionButton)
{
m_functionButton->IsEnabled = false;
}
}
}
void EquationTextBox::OnEquationButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
{
EquationButtonClicked(this, ref new RoutedEventArgs());
SetEquationButtonTooltipAndAutomationName();
}
void EquationTextBox::OnRemoveButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (IsAddEquationMode)
{
// Don't remove the last equation
return;
}
if (m_richEditBox != nullptr)
{
m_richEditBox->MathText = L"";
}
RemoveButtonClicked(this, ref new RoutedEventArgs());
if (m_functionButton)
{
m_functionButton->IsEnabled = false;
}
if (m_equationButton)
{
IsEquationLineDisabled = false;
}
TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::RemoveFunction, GraphButtonValue::None);
VisualStateManager::GoToState(this, "Normal", true);
}
void EquationTextBox::OnColorChooserButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (ColorChooserFlyout != nullptr && m_richEditBox != nullptr)
{
ColorChooserFlyout->ShowAt(m_richEditBox);
TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::StylePicker, GraphButtonValue::None);
}
}
void EquationTextBox::OnFunctionMenuButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
{
// Submit the equation before trying to analyze it if invoked from context menu
if (m_richEditBox != nullptr)
{
m_richEditBox->SubmitEquation(::EquationSubmissionSource::FOCUS_LOST);
}
KeyGraphFeaturesButtonClicked(this, ref new RoutedEventArgs());
}
void EquationTextBox::OnFunctionButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
{
KeyGraphFeaturesButtonClicked(this, ref new RoutedEventArgs());
}
void EquationTextBox::OnCutClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->Selection->Cut();
}
}
void EquationTextBox::OnCopyClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->Selection->Copy();
}
}
void EquationTextBox::OnPasteClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->Selection->Paste(0);
}
}
void EquationTextBox::OnSelectAllClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->Selection->SetRange(0, m_richEditBox->TextDocument->Selection->EndPosition);
}
}
void EquationTextBox::OnUndoClicked(Object ^ sender, RoutedEventArgs ^ e)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->Undo();
}
}
void EquationTextBox::UpdateButtonsVisualState()
{
String ^ state;
if (m_HasFocus && RichEditHasContent())
{
state = "ButtonVisible";
}
else if (IsAddEquationMode)
{
state = "ButtonHideRemove";
}
else
{
state = "ButtonCollapsed";
}
VisualStateManager::GoToState(this, state, true);
}
void EquationTextBox::UpdateCommonVisualState()
{
String ^ state = nullptr;
bool richEditHasContent = RichEditHasContent();
if (m_HasFocus && HasError)
{
state = "FocusedError";
}
else if (IsAddEquationMode && m_HasFocus && !richEditHasContent)
{
state = "AddEquationFocused";
}
else if (m_HasFocus)
{
state = "Focused";
}
else if (IsAddEquationMode && m_isPointerOver && !richEditHasContent)
{
state = "AddEquation";
}
else if (HasError && (m_isPointerOver || m_isColorChooserFlyoutOpen))
{
state = "PointerOverError";
}
else if (m_isPointerOver || m_isColorChooserFlyoutOpen)
{
state = "PointerOver";
}
else if (HasError)
{
state = "Error";
}
else if (IsAddEquationMode)
{
state = "AddEquation";
}
else
{
state = "Normal";
}
VisualStateManager::GoToState(this, state, false);
}
void EquationTextBox::OnHasErrorPropertyChanged(bool, bool)
{
UpdateCommonVisualState();
}
void EquationTextBox::SetEquationText(Platform::String ^ equationText)
{
if (m_richEditBox != nullptr)
{
m_richEditBox->MathText = equationText;
}
}
bool EquationTextBox::RichEditHasContent()
{
String ^ text;
if (m_richEditBox != nullptr)
{
m_richEditBox->TextDocument->GetText(Windows::UI::Text::TextGetOptions::NoHidden, &text);
}
return !text->IsEmpty();
}
void EquationTextBox::OnRichEditMenuOpened(Object ^ /*sender*/, Object ^ /*args*/)
{
if (m_removeMenuItem != nullptr)
{
m_removeMenuItem->IsEnabled = !IsAddEquationMode;
}
if (m_kgfEquationMenuItem != nullptr)
{
m_kgfEquationMenuItem->IsEnabled = m_HasFocus && !HasError && RichEditHasContent();
}
if (m_colorChooserMenuItem != nullptr)
{
m_colorChooserMenuItem->IsEnabled = !HasError && !IsAddEquationMode;
}
if (m_richEditBox != nullptr && m_cutMenuItem != nullptr)
{
m_cutMenuItem->IsEnabled = m_richEditBox->TextDocument->CanCopy();
}
if (m_richEditBox != nullptr && m_copyMenuItem != nullptr)
{
m_copyMenuItem->IsEnabled = m_richEditBox->TextDocument->CanCopy();
}
if (m_richEditBox != nullptr && m_pasteMenuItem != nullptr)
{
m_pasteMenuItem->IsEnabled = m_richEditBox->TextDocument->CanPaste();
}
if (m_richEditBox != nullptr && m_undoMenuItem != nullptr)
{
m_undoMenuItem->IsEnabled = m_richEditBox->TextDocument->CanUndo();
}
}
void EquationTextBox::OnIsAddEquationModePropertyChanged(bool /*oldValue*/, bool /*newValue*/)
{
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
void EquationTextBox::FocusTextBox()
{
if (m_richEditBox != nullptr)
{
FocusManager::TryFocusAsync(m_richEditBox, ::FocusState::Programmatic);
}
}
void EquationTextBox::OnEquationSubmitted(Platform::Object ^ sender, MathRichEditBoxSubmission ^ args)
{
if (args->HasTextChanged)
{
if (m_functionButton && m_richEditBox->MathText != L"")
{
m_functionButton->IsEnabled = true;
}
}
EquationSubmitted(this, args);
}
void EquationTextBox::OnEquationFormatRequested(Object ^ sender, MathRichEditBoxFormatRequest ^ args)
{
EquationFormatRequested(this, args);
}
void EquationTextBox::SetEquationButtonTooltipAndAutomationName()
{
auto toolTip = ref new ToolTip();
auto resProvider = AppResourceProvider::GetInstance();
auto equationButtonMessage = LocalizationStringUtil::GetLocalizedString(
IsEquationLineDisabled ? resProvider->GetResourceString(L"showEquationButtonAutomationName")
: resProvider->GetResourceString(L"hideEquationButtonAutomationName"),
EquationButtonContentIndex);
auto equationButtonTooltip = LocalizationStringUtil::GetLocalizedString(
IsEquationLineDisabled ? resProvider->GetResourceString(L"showEquationButtonToolTip") : resProvider->GetResourceString(L"hideEquationButtonToolTip"));
toolTip->Content = equationButtonTooltip;
ToolTipService::SetToolTip(m_equationButton, toolTip);
AutomationProperties::SetName(m_equationButton, equationButtonMessage);
}
void EquationTextBox::OnEquationButtonContentIndexPropertyChanged(String ^ /*oldValue*/, String ^ newValue)
{
SetEquationButtonTooltipAndAutomationName();
}

View File

@@ -0,0 +1,626 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
using System;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
namespace CalculatorApp
{
namespace Controls
{
public sealed class EquationTextBox : Windows.UI.Xaml.Controls.Control
{
public EquationTextBox()
{
}
public Windows.UI.Xaml.Media.SolidColorBrush EquationColor
{
get { return (Windows.UI.Xaml.Media.SolidColorBrush)GetValue(EquationColorProperty); }
set { SetValue(EquationColorProperty, value); }
}
// Using a DependencyProperty as the backing store for EquationColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EquationColorProperty =
DependencyProperty.Register(nameof(EquationColor), typeof(Windows.UI.Xaml.Media.SolidColorBrush), typeof(EquationTextBox), new PropertyMetadata(default(Windows.UI.Xaml.Media.SolidColorBrush)));
public Windows.UI.Xaml.Media.SolidColorBrush EquationButtonForegroundColor
{
get { return (Windows.UI.Xaml.Media.SolidColorBrush)GetValue(EquationButtonForegroundColorProperty); }
set { SetValue(EquationButtonForegroundColorProperty, value); }
}
// Using a DependencyProperty as the backing store for EquationButtonForegroundColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EquationButtonForegroundColorProperty =
DependencyProperty.Register(nameof(EquationButtonForegroundColor), typeof(Windows.UI.Xaml.Media.SolidColorBrush), typeof(EquationTextBox), new PropertyMetadata(default(Windows.UI.Xaml.Media.SolidColorBrush)));
public Windows.UI.Xaml.Controls.Flyout ColorChooserFlyout
{
get { return (Windows.UI.Xaml.Controls.Flyout)GetValue(ColorChooserFlyoutProperty); }
set { SetValue(ColorChooserFlyoutProperty, value); }
}
// Using a DependencyProperty as the backing store for ColorChooserFlyout. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ColorChooserFlyoutProperty =
DependencyProperty.Register(nameof(ColorChooserFlyout), typeof(Windows.UI.Xaml.Controls.Flyout), typeof(EquationTextBox), new PropertyMetadata(default(Windows.UI.Xaml.Controls.Flyout)));
public string EquationButtonContentIndex
{
get { return (string)GetValue(EquationButtonContentIndexProperty); }
set { SetValue(EquationButtonContentIndexProperty, value); }
}
// Using a DependencyProperty as the backing store for EquationButtonContentIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EquationButtonContentIndexProperty =
DependencyProperty.Register(nameof(EquationButtonContentIndex), typeof(string), typeof(EquationTextBox), new PropertyMetadata(string.Empty, (sender, args) =>
{
var self = (EquationTextBox)sender;
self.OnEquationButtonContentIndexPropertyChanged((string)args.OldValue, (string)args.NewValue);
}));
public string MathEquation
{
get { return (string)GetValue(MathEquationProperty); }
set { SetValue(MathEquationProperty, value); }
}
// Using a DependencyProperty as the backing store for MathEquation. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MathEquationProperty =
DependencyProperty.Register(nameof(MathEquation), typeof(string), typeof(EquationTextBox), new PropertyMetadata(string.Empty));
public bool HasError
{
get { return (bool)GetValue(HasErrorProperty); }
set { SetValue(HasErrorProperty, value); }
}
// Using a DependencyProperty as the backing store for HasError. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HasErrorProperty =
DependencyProperty.Register(nameof(HasError), typeof(bool), typeof(EquationTextBox), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (EquationTextBox)sender;
self.OnHasErrorPropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
public bool IsAddEquationMode
{
get { return (bool)GetValue(IsAddEquationModeProperty); }
set { SetValue(IsAddEquationModeProperty, value); }
}
// Using a DependencyProperty as the backing store for IsAddEquationMode. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsAddEquationModeProperty =
DependencyProperty.Register(nameof(IsAddEquationMode), typeof(bool), typeof(EquationTextBox), new PropertyMetadata(default(bool), (sender, args) =>
{
var self = (EquationTextBox)sender;
self.OnIsAddEquationModePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
}));
public string ErrorText
{
get { return (string)GetValue(ErrorTextProperty); }
set { SetValue(ErrorTextProperty, value); }
}
// Using a DependencyProperty as the backing store for ErrorText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ErrorTextProperty =
DependencyProperty.Register(nameof(ErrorText), typeof(string), typeof(EquationTextBox), new PropertyMetadata(string.Empty));
public bool IsEquationLineDisabled
{
get { return (bool)GetValue(IsEquationLineDisabledProperty); }
set { SetValue(IsEquationLineDisabledProperty, value); }
}
// Using a DependencyProperty as the backing store for IsEquationLineDisabled. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsEquationLineDisabledProperty =
DependencyProperty.Register(nameof(IsEquationLineDisabled), typeof(bool), typeof(EquationTextBox), new PropertyMetadata(default(bool)));
public bool HasFocus
{
get => m_HasFocus;
}
private bool m_HasFocus;
public event Windows.UI.Xaml.RoutedEventHandler RemoveButtonClicked;
public event Windows.UI.Xaml.RoutedEventHandler KeyGraphFeaturesButtonClicked;
public event System.EventHandler<MathRichEditBoxSubmission> EquationSubmitted;
public event System.EventHandler<MathRichEditBoxFormatRequest> EquationFormatRequested;
public event Windows.UI.Xaml.RoutedEventHandler EquationButtonClicked;
public void SetEquationText(string equationText)
{
if (m_richEditBox != null)
{
m_richEditBox.MathText = equationText;
}
}
public void FocusTextBox()
{
if (m_richEditBox != null)
{
_ = FocusManager.TryFocusAsync(m_richEditBox, FocusState.Programmatic);
}
}
protected override void OnApplyTemplate()
{
m_equationButton = GetTemplateChild("EquationButton") as ToggleButton;
m_richEditBox = GetTemplateChild("MathRichEditBox") as MathRichEditBox;
m_deleteButton = GetTemplateChild("DeleteButton") as Button;
m_removeButton = GetTemplateChild("RemoveButton") as Button;
m_functionButton = GetTemplateChild("FunctionButton") as Button;
m_colorChooserButton = GetTemplateChild("ColorChooserButton") as ToggleButton;
m_richEditContextMenu = GetTemplateChild("MathRichEditContextMenu") as MenuFlyout;
m_kgfEquationMenuItem = GetTemplateChild("FunctionAnalysisMenuItem") as MenuFlyoutItem;
m_removeMenuItem = GetTemplateChild("RemoveFunctionMenuItem") as MenuFlyoutItem;
m_colorChooserMenuItem = GetTemplateChild("ChangeFunctionStyleMenuItem") as MenuFlyoutItem;
m_cutMenuItem = GetTemplateChild("CutMenuItem") as MenuFlyoutItem;
m_copyMenuItem = GetTemplateChild("CopyMenuItem") as MenuFlyoutItem;
m_pasteMenuItem = GetTemplateChild("PasteMenuItem") as MenuFlyoutItem;
m_undoMenuItem = GetTemplateChild("UndoMenuItem") as MenuFlyoutItem;
m_selectAllMenuItem = GetTemplateChild("SelectAllMenuItem") as MenuFlyoutItem;
var resProvider = AppResourceProvider.GetInstance();
if (m_richEditBox != null)
{
m_richEditBox.GotFocus += OnRichEditBoxGotFocus;
m_richEditBox.LostFocus += OnRichEditBoxLostFocus;
m_richEditBox.TextChanged += OnRichEditTextChanged;
m_richEditBox.SelectionFlyout = null;
m_richEditBox.EquationSubmitted += OnEquationSubmitted;
m_richEditBox.FormatRequest += OnEquationFormatRequested;
}
if (m_equationButton != null)
{
m_equationButton.Click += OnEquationButtonClicked;
}
if (m_richEditContextMenu != null)
{
m_richEditContextMenu.Opened += OnRichEditMenuOpened;
}
if (m_deleteButton != null)
{
m_deleteButton.Click += OnDeleteButtonClicked;
}
if (m_removeButton != null)
{
m_removeButton.Click += OnRemoveButtonClicked;
}
if (m_removeMenuItem != null)
{
m_removeMenuItem.Text = resProvider.GetResourceString("removeMenuItem");
m_removeMenuItem.Click += OnRemoveButtonClicked;
}
if (m_colorChooserButton != null)
{
m_colorChooserButton.Click += OnColorChooserButtonClicked;
}
if (m_colorChooserMenuItem != null)
{
m_colorChooserMenuItem.Text = resProvider.GetResourceString("colorChooserMenuItem");
m_colorChooserMenuItem.Click += OnColorChooserButtonClicked;
}
if (m_functionButton != null)
{
m_functionButton.Click += OnFunctionButtonClicked;
m_functionButton.IsEnabled = false;
}
if (m_kgfEquationMenuItem != null)
{
m_kgfEquationMenuItem.Text = resProvider.GetResourceString("functionAnalysisMenuItem");
m_kgfEquationMenuItem.Click += OnFunctionMenuButtonClicked;
}
if (ColorChooserFlyout != null)
{
ColorChooserFlyout.Opened += OnColorFlyoutOpened;
ColorChooserFlyout.Closed += OnColorFlyoutClosed;
}
if (m_cutMenuItem != null)
{
m_cutMenuItem.Click += OnCutClicked;
}
if (m_copyMenuItem != null)
{
m_copyMenuItem.Click += OnCopyClicked;
}
if (m_pasteMenuItem != null)
{
m_pasteMenuItem.Click += OnPasteClicked;
}
if (m_undoMenuItem != null)
{
m_undoMenuItem.Click += OnUndoClicked;
}
if (m_selectAllMenuItem != null)
{
m_selectAllMenuItem.Click += OnSelectAllClicked;
}
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
protected override void OnPointerEntered(PointerRoutedEventArgs e)
{
m_isPointerOver = true;
UpdateCommonVisualState();
}
protected override void OnPointerExited(PointerRoutedEventArgs e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
protected override void OnPointerCanceled(PointerRoutedEventArgs e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
protected override void OnPointerCaptureLost(PointerRoutedEventArgs e)
{
m_isPointerOver = false;
UpdateCommonVisualState();
}
private void OnIsAddEquationModePropertyChanged(bool oldValue, bool newValue)
{
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void UpdateCommonVisualState()
{
string state = null;
bool richEditHasContent = RichEditHasContent();
if (m_HasFocus && HasError)
{
state = "FocusedError";
}
else if (IsAddEquationMode && m_HasFocus && !richEditHasContent)
{
state = "AddEquationFocused";
}
else if (m_HasFocus)
{
state = "Focused";
}
else if (IsAddEquationMode && m_isPointerOver && !richEditHasContent)
{
state = "AddEquation";
}
else if (HasError && (m_isPointerOver || m_isColorChooserFlyoutOpen))
{
state = "PointerOverError";
}
else if (m_isPointerOver || m_isColorChooserFlyoutOpen)
{
state = "PointerOver";
}
else if (HasError)
{
state = "Error";
}
else if (IsAddEquationMode)
{
state = "AddEquation";
}
else
{
state = "Normal";
}
VisualStateManager.GoToState(this, state, false);
}
private void UpdateButtonsVisualState()
{
string state;
if (m_HasFocus && RichEditHasContent())
{
state = "ButtonVisible";
}
else if (IsAddEquationMode)
{
state = "ButtonHideRemove";
}
else
{
state = "ButtonCollapsed";
}
VisualStateManager.GoToState(this, state, true);
}
private bool RichEditHasContent()
{
string text = null;
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.GetText(Windows.UI.Text.TextGetOptions.NoHidden, out text);
}
return !string.IsNullOrEmpty(text);
}
private void OnRichEditBoxGotFocus(object sender, RoutedEventArgs e)
{
m_HasFocus = true;
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void OnRichEditBoxLostFocus(object sender, RoutedEventArgs e)
{
if (!m_richEditBox.ContextFlyout.IsOpen)
{
m_HasFocus = false;
}
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void OnRichEditTextChanged(object sender, RoutedEventArgs e)
{
UpdateCommonVisualState();
UpdateButtonsVisualState();
}
private void OnDeleteButtonClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.SetText(TextSetOptions.None, "");
if (m_functionButton != null)
{
m_functionButton.IsEnabled = false;
}
}
}
private void OnEquationButtonClicked(object sender, RoutedEventArgs e)
{
EquationButtonClicked?.Invoke(this, new RoutedEventArgs());
SetEquationButtonTooltipAndAutomationName();
}
private void OnRemoveButtonClicked(object sender, RoutedEventArgs e)
{
if (IsAddEquationMode)
{
// Don't remove the last equation
return;
}
if (m_richEditBox != null)
{
m_richEditBox.MathText = "";
}
RemoveButtonClicked?.Invoke(this, new RoutedEventArgs());
if (m_functionButton != null)
{
m_functionButton.IsEnabled = false;
}
if (m_equationButton != null)
{
IsEquationLineDisabled = false;
}
TraceLogger.GetInstance().LogGraphButtonClicked(GraphButton.RemoveFunction, GraphButtonValue.None);
VisualStateManager.GoToState(this, "Normal", true);
}
private void OnColorChooserButtonClicked(object sender, RoutedEventArgs e)
{
if (ColorChooserFlyout != null && m_richEditBox != null)
{
ColorChooserFlyout.ShowAt(m_richEditBox);
TraceLogger.GetInstance().LogGraphButtonClicked(GraphButton.StylePicker, GraphButtonValue.None);
}
}
private void OnFunctionButtonClicked(object sender, RoutedEventArgs e)
{
KeyGraphFeaturesButtonClicked?.Invoke(this, new RoutedEventArgs());
}
private void OnFunctionMenuButtonClicked(object sender, RoutedEventArgs e)
{
// Submit the equation before trying to analyze it if invoked from context menu
if (m_richEditBox != null)
{
m_richEditBox.SubmitEquation(EquationSubmissionSource.FOCUS_LOST);
}
KeyGraphFeaturesButtonClicked?.Invoke(this, new RoutedEventArgs());
}
private void OnRichEditMenuOpened(object sender, object args)
{
if (m_removeMenuItem != null)
{
m_removeMenuItem.IsEnabled = !IsAddEquationMode;
}
if (m_kgfEquationMenuItem != null)
{
m_kgfEquationMenuItem.IsEnabled = m_HasFocus && !HasError && RichEditHasContent();
}
if (m_colorChooserMenuItem != null)
{
m_colorChooserMenuItem.IsEnabled = !HasError && !IsAddEquationMode;
}
if (m_richEditBox != null && m_cutMenuItem != null)
{
m_cutMenuItem.IsEnabled = m_richEditBox.TextDocument.CanCopy();
}
if (m_richEditBox != null && m_copyMenuItem != null)
{
m_copyMenuItem.IsEnabled = m_richEditBox.TextDocument.CanCopy();
}
if (m_richEditBox != null && m_pasteMenuItem != null)
{
m_pasteMenuItem.IsEnabled = m_richEditBox.TextDocument.CanPaste();
}
if (m_richEditBox != null && m_undoMenuItem != null)
{
m_undoMenuItem.IsEnabled = m_richEditBox.TextDocument.CanUndo();
}
}
private void OnCutClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.Cut();
}
}
private void OnCopyClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.Copy();
}
}
private void OnPasteClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.Paste(0);
}
}
private void OnUndoClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Undo();
}
}
private void OnSelectAllClicked(object sender, RoutedEventArgs e)
{
if (m_richEditBox != null)
{
m_richEditBox.TextDocument.Selection.SetRange(0, m_richEditBox.TextDocument.Selection.EndPosition);
}
}
private void OnColorFlyoutOpened(object sender, object e)
{
m_isColorChooserFlyoutOpen = true;
UpdateCommonVisualState();
}
private void OnColorFlyoutClosed(object sender, object e)
{
m_colorChooserButton.IsChecked = false;
m_isColorChooserFlyoutOpen = false;
UpdateCommonVisualState();
}
private void OnHasErrorPropertyChanged(bool oldValue, bool newValue)
{
UpdateCommonVisualState();
}
private void OnEquationButtonContentIndexPropertyChanged(string oldValue, string newValue)
{
SetEquationButtonTooltipAndAutomationName();
}
private void SetEquationButtonTooltipAndAutomationName()
{
var toolTip = new ToolTip();
var resProvider = AppResourceProvider.GetInstance();
var equationButtonMessage = LocalizationStringUtil.GetLocalizedString(
IsEquationLineDisabled ? resProvider.GetResourceString("showEquationButtonAutomationName")
: resProvider.GetResourceString("hideEquationButtonAutomationName"),
EquationButtonContentIndex);
var equationButtonTooltip = LocalizationStringUtil.GetLocalizedString(
IsEquationLineDisabled ? resProvider.GetResourceString("showEquationButtonToolTip") : resProvider.GetResourceString("hideEquationButtonToolTip"));
toolTip.Content = equationButtonTooltip;
ToolTipService.SetToolTip(m_equationButton, toolTip);
AutomationProperties.SetName(m_equationButton, equationButtonMessage);
}
private CalculatorApp.Controls.MathRichEditBox m_richEditBox;
private Windows.UI.Xaml.Controls.Primitives.ToggleButton m_equationButton;
private Windows.UI.Xaml.Controls.Button m_deleteButton;
private Windows.UI.Xaml.Controls.Button m_removeButton;
private Windows.UI.Xaml.Controls.Button m_functionButton;
private Windows.UI.Xaml.Controls.Primitives.ToggleButton m_colorChooserButton;
private Windows.UI.Xaml.Controls.MenuFlyout m_richEditContextMenu;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_cutMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_copyMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_pasteMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_undoMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_selectAllMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_kgfEquationMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_removeMenuItem;
private Windows.UI.Xaml.Controls.MenuFlyoutItem m_colorChooserMenuItem;
private bool m_isPointerOver;
private bool m_isColorChooserFlyoutOpen;
private void OnEquationSubmitted(object sender, MathRichEditBoxSubmission args)
{
if (args.HasTextChanged)
{
if (m_functionButton != null && m_richEditBox.MathText != "")
{
m_functionButton.IsEnabled = true;
}
}
EquationSubmitted?.Invoke(this, args);
}
private void OnEquationFormatRequested(object sender, MathRichEditBoxFormatRequest args)
{
EquationFormatRequested?.Invoke(this, args);
}
}
}
}

View File

@@ -1,105 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
#include "CalcViewModel/GraphingCalculator/EquationViewModel.h"
#include "Calculator/Controls/MathRichEditBox.h"
#include "CalcViewModel/Common/TraceLogger.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class EquationTextBox sealed : public Windows::UI::Xaml::Controls::Control
{
public:
EquationTextBox();
DEPENDENCY_PROPERTY_OWNER(EquationTextBox);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::SolidColorBrush ^, EquationColor);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::SolidColorBrush ^, EquationButtonForegroundColor);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::Flyout ^, ColorChooserFlyout);
DEPENDENCY_PROPERTY_WITH_CALLBACK(Platform::String ^, EquationButtonContentIndex);
DEPENDENCY_PROPERTY(Platform::String ^, MathEquation);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, HasError);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, IsAddEquationMode);
DEPENDENCY_PROPERTY(Platform::String ^, ErrorText);
DEPENDENCY_PROPERTY(bool, IsEquationLineDisabled);
PROPERTY_R(bool, HasFocus);
event Windows::UI::Xaml::RoutedEventHandler ^ RemoveButtonClicked;
event Windows::UI::Xaml::RoutedEventHandler ^ KeyGraphFeaturesButtonClicked;
event Windows::Foundation::EventHandler<MathRichEditBoxSubmission ^> ^ EquationSubmitted;
event Windows::Foundation::EventHandler<MathRichEditBoxFormatRequest ^> ^ EquationFormatRequested;
event Windows::UI::Xaml::RoutedEventHandler ^ EquationButtonClicked;
void SetEquationText(Platform::String ^ equationText);
void FocusTextBox();
protected:
virtual void OnApplyTemplate() override;
virtual void OnPointerEntered(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
virtual void OnPointerExited(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
virtual void OnPointerCanceled(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
virtual void OnPointerCaptureLost(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnIsAddEquationModePropertyChanged(bool oldValue, bool newValue);
private:
void UpdateCommonVisualState();
void UpdateButtonsVisualState();
bool RichEditHasContent();
void OnRichEditBoxGotFocus(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnRichEditBoxLostFocus(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnRichEditTextChanged(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnDeleteButtonClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnEquationButtonClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnRemoveButtonClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnColorChooserButtonClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnFunctionButtonClicked(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnFunctionMenuButtonClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnRichEditMenuOpened(Platform::Object ^ sender, Platform::Object ^ args);
void OnCutClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnCopyClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnPasteClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnUndoClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnSelectAllClicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnColorFlyoutOpened(Platform::Object ^ sender, Platform::Object ^ e);
void OnColorFlyoutClosed(Platform::Object ^ sender, Platform::Object ^ e);
void OnHasErrorPropertyChanged(bool oldValue, bool newValue);
void OnEquationButtonContentIndexPropertyChanged(Platform::String ^ /*oldValue*/, Platform::String ^ newValue);
void SetEquationButtonTooltipAndAutomationName();
CalculatorApp::Controls::MathRichEditBox ^ m_richEditBox;
Windows::UI::Xaml::Controls::Primitives::ToggleButton ^ m_equationButton;
Windows::UI::Xaml::Controls::Button ^ m_deleteButton;
Windows::UI::Xaml::Controls::Button ^ m_removeButton;
Windows::UI::Xaml::Controls::Button ^ m_functionButton;
Windows::UI::Xaml::Controls::Primitives::ToggleButton ^ m_colorChooserButton;
Windows::UI::Xaml::Controls::MenuFlyout^ m_richEditContextMenu;
Windows::UI::Xaml::Controls::MenuFlyoutItem ^ m_cutMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem ^ m_copyMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem ^ m_pasteMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem ^ m_undoMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem ^ m_selectAllMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem^ m_kgfEquationMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem^ m_removeMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem^ m_colorChooserMenuItem;
bool m_isPointerOver;
bool m_isColorChooserFlyoutOpen;
void OnEquationSubmitted(Platform::Object ^ sender, CalculatorApp::Controls::MathRichEditBoxSubmission ^ args);
void OnEquationFormatRequested(Platform::Object ^ sender, CalculatorApp::Controls::MathRichEditBoxFormatRequest ^ args);
};
}
}

View File

@@ -1,47 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "FlipButtons.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Controls;
using namespace Windows::System;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Data;
using namespace Platform;
using namespace Windows::Foundation::Collections;
DEPENDENCY_PROPERTY_INITIALIZATION(FlipButtons, ButtonId);
DEPENDENCY_PROPERTY_INITIALIZATION(FlipButtons, HoverBackground);
DEPENDENCY_PROPERTY_INITIALIZATION(FlipButtons, HoverForeground);
DEPENDENCY_PROPERTY_INITIALIZATION(FlipButtons, PressBackground);
DEPENDENCY_PROPERTY_INITIALIZATION(FlipButtons, PressForeground);
void FlipButtons::OnKeyDown(KeyRoutedEventArgs ^ e)
{
// Ignore the Enter key
if (e->Key == VirtualKey::Enter)
{
return;
}
ToggleButton::OnKeyDown(e);
}
void FlipButtons::OnKeyUp(KeyRoutedEventArgs ^ e)
{
// Ignore the Enter key
if (e->Key == VirtualKey::Enter)
{
return;
}
ToggleButton::OnKeyUp(e);
}
void FlipButtons::OnButtonIdPropertyChanged(NumbersAndOperatorsEnum /*oldValue*/, NumbersAndOperatorsEnum newValue)
{
this->CommandParameter = newValue;
}

View File

@@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
namespace CalculatorApp
{
namespace Controls
{
public sealed class FlipButtons : Windows.UI.Xaml.Controls.Primitives.ToggleButton
{
public NumbersAndOperatorsEnum ButtonId
{
get { return (NumbersAndOperatorsEnum)GetValue(ButtonIdProperty); }
set { SetValue(ButtonIdProperty, value); }
}
// Using a DependencyProperty as the backing store for ButtonId. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ButtonIdProperty =
DependencyProperty.Register(nameof(ButtonId), typeof(NumbersAndOperatorsEnum), typeof(FlipButtons), new PropertyMetadata(default(NumbersAndOperatorsEnum)));
public Windows.UI.Xaml.Media.Brush HoverBackground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(HoverBackgroundProperty); }
set { SetValue(HoverBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverBackgroundProperty =
DependencyProperty.Register(nameof(HoverBackground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush HoverForeground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(HoverForegroundProperty); }
set { SetValue(HoverForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverForegroundProperty =
DependencyProperty.Register(nameof(HoverForeground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush PressBackground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(PressBackgroundProperty); }
set { SetValue(PressBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for PressBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressBackgroundProperty =
DependencyProperty.Register(nameof(PressBackground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
public Windows.UI.Xaml.Media.Brush PressForeground
{
get { return (Windows.UI.Xaml.Media.Brush)GetValue(PressForegroundProperty); }
set { SetValue(PressForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for PressForeground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressForegroundProperty =
DependencyProperty.Register(nameof(PressForeground), typeof(Windows.UI.Xaml.Media.Brush), typeof(FlipButtons), new PropertyMetadata(default(Windows.UI.Xaml.Media.Brush)));
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
// Ignore the Enter key
if (e.Key == VirtualKey.Enter)
{
return;
}
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyRoutedEventArgs e)
{
// Ignore the Enter key
if (e.Key == VirtualKey.Enter)
{
return;
}
base.OnKeyUp(e);
}
private void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue)
{
CommandParameter = newValue;
}
}
}
}

View File

@@ -1,33 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
#include "CalcViewModel/Common/CalculatorButtonUser.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class FlipButtons sealed : Windows::UI::Xaml::Controls::Primitives::ToggleButton
{
public:
DEPENDENCY_PROPERTY_OWNER(FlipButtons);
DEPENDENCY_PROPERTY_WITH_CALLBACK(NumbersAndOperatorsEnum, ButtonId);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, HoverBackground);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, HoverForeground);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, PressBackground);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::Brush ^, PressForeground);
protected:
virtual void OnKeyDown(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
virtual void OnKeyUp(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
private:
void OnButtonIdPropertyChanged(NumbersAndOperatorsEnum oldValue, NumbersAndOperatorsEnum newValue);
};
}
}

View File

@@ -1,73 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// HorizontalNoOverflowStackPanel.xaml.cpp
// Implementation of the HorizontalNoOverflowStackPanel class
//
#include "pch.h"
#include "HorizontalNoOverflowStackPanel.h"
using namespace std;
using namespace CalculatorApp::Controls;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
Size HorizontalNoOverflowStackPanel::MeasureOverride(Size availableSize)
{
float maxHeight = 0;
float width = 0;
for (auto child : Children)
{
child->Measure(Size(numeric_limits<float>::infinity(), numeric_limits<float>::infinity()));
maxHeight = max(maxHeight, child->DesiredSize.Height);
width += child->DesiredSize.Width;
}
return Size(min(width, availableSize.Width), min(availableSize.Height, maxHeight));
}
bool HorizontalNoOverflowStackPanel::ShouldPrioritizeLastItem()
{
return false;
}
Size HorizontalNoOverflowStackPanel::ArrangeOverride(Size finalSize)
{
if (Children->Size == 0)
{
return finalSize;
}
float posX = 0;
auto lastChild = Children->GetAt(Children->Size - 1);
float lastChildWidth = 0;
if (Children->Size > 2 && ShouldPrioritizeLastItem())
{
lastChildWidth = lastChild->DesiredSize.Width;
}
for (auto item : Children)
{
auto widthAvailable = finalSize.Width - posX;
if (item != lastChild)
{
widthAvailable -= lastChildWidth;
}
float itemWidth = item->DesiredSize.Width;
if (widthAvailable > 0 && itemWidth <= widthAvailable)
{
// stack the items horizontally (left to right)
item->Arrange(Rect(posX, 0, itemWidth, finalSize.Height));
AutomationProperties::SetAccessibilityView(item, ::AccessibilityView::Content);
posX += item->RenderSize.Width;
}
else
{
// Not display the item
item->Arrange(Rect(0, 0, 0, 0));
AutomationProperties::SetAccessibilityView(item, ::AccessibilityView::Raw);
}
}
return finalSize;
}

View File

@@ -0,0 +1,83 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// HorizontalNoOverflowStackPanel.h
// Declaration of the HorizontalNoOverflowStackPanel class
//
using System;
using Windows.Foundation;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
namespace CalculatorApp
{
namespace Controls
{
public class HorizontalNoOverflowStackPanel : Windows.UI.Xaml.Controls.Panel
{
// Prioritize the last item over all other items (except the first one)
internal HorizontalNoOverflowStackPanel()
{ }
protected override Size MeasureOverride(Size availableSize)
{
float maxHeight = 0;
float width = 0;
foreach (var child in Children)
{
child.Measure(new Size(float.PositiveInfinity, float.PositiveInfinity));
maxHeight = (float)Math.Max(maxHeight, child.DesiredSize.Height);
width += (float)child.DesiredSize.Width;
}
return new Size(Math.Min(width, availableSize.Width), Math.Min(availableSize.Height, maxHeight));
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Children.Count == 0)
{
return finalSize;
}
float posX = 0;
var lastChild = Children[Children.Count - 1];
float lastChildWidth = 0;
if (Children.Count > 2 && ShouldPrioritizeLastItem())
{
lastChildWidth = (float)lastChild.DesiredSize.Width;
}
foreach (var item in Children)
{
var widthAvailable = finalSize.Width - posX;
if (item != lastChild)
{
widthAvailable -= lastChildWidth;
}
float itemWidth = (float)item.DesiredSize.Width;
if (widthAvailable > 0 && itemWidth <= widthAvailable)
{
// stack the items horizontally (left to right)
item.Arrange(new Rect(posX, 0, itemWidth, finalSize.Height));
AutomationProperties.SetAccessibilityView(item, AccessibilityView.Content);
posX += (float)item.RenderSize.Width;
}
else
{
// Not display the item
item.Arrange(new Rect(0, 0, 0, 0));
AutomationProperties.SetAccessibilityView(item, AccessibilityView.Raw);
}
}
return finalSize;
}
protected virtual bool ShouldPrioritizeLastItem()
{
return false;
}
}
}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// HorizontalNoOverflowStackPanel.h
// Declaration of the HorizontalNoOverflowStackPanel class
//
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class HorizontalNoOverflowStackPanel : public Windows::UI::Xaml::Controls::Panel
{
DEPENDENCY_PROPERTY_OWNER(HorizontalNoOverflowStackPanel);
// Prioritize the last item over all other items (except the first one)
internal : HorizontalNoOverflowStackPanel()
{
}
protected:
virtual Windows::Foundation::Size MeasureOverride(Windows::Foundation::Size availableSize) override;
virtual Windows::Foundation::Size ArrangeOverride(Windows::Foundation::Size finalSize) override;
virtual bool ShouldPrioritizeLastItem();
};
}
}

View File

@@ -1,229 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "MathRichEditBox.h"
using namespace Platform;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace std;
using namespace Windows::ApplicationModel;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Text;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::System;
using namespace Microsoft::WRL;
DEPENDENCY_PROPERTY_INITIALIZATION(MathRichEditBox, MathText);
// TODO remove when Windows 10 version 2004 SDK is adopted
namespace Windows_2004_Prerelease
{
enum RichEditMathMode : int
{
NoMath,
MathOnly,
};
MIDL_INTERFACE("619c20f2-cb3b-4521-981f-2865b1b93f04")
ITextDocument4 : public IInspectable
{
public:
virtual HRESULT STDMETHODCALLTYPE SetMath(HSTRING value) = 0;
virtual HRESULT STDMETHODCALLTYPE GetMath(HSTRING * value) = 0;
virtual HRESULT STDMETHODCALLTYPE SetMathMode(RichEditMathMode mathMode) = 0;
};
}
MathRichEditBox::MathRichEditBox()
{
static LimitedAccessFeatureStatus m_lafResultStatus;
String ^ packageName = Package::Current->Id->Name;
if (packageName == L"Microsoft.WindowsCalculator.Dev")
{
m_lafResultStatus = LimitedAccessFeatures::TryUnlockFeature(
"com.microsoft.windows.richeditmath",
"BeDD/jxKhz/yfVNA11t4uA==", // Microsoft.WindowsCalculator.Dev
"8wekyb3d8bbwe has registered their use of com.microsoft.windows.richeditmath with Microsoft and agrees to the terms of use.")
->Status;
}
else if (packageName == L"Microsoft.WindowsCalculator")
{
m_lafResultStatus = LimitedAccessFeatures::TryUnlockFeature(
"com.microsoft.windows.richeditmath",
"pfanNuxnzo+mAkBQ3N/rGQ==", // Microsoft.WindowsCalculator
"8wekyb3d8bbwe has registered their use of com.microsoft.windows.richeditmath with Microsoft and agrees to the terms of use.")
->Status;
}
// TODO when Windows 10 version 2004 SDK is adopted, replace with:
// TextDocument->SetMathMode(Windows::UI::Text::RichEditMathMode::MathOnly);
ComPtr<Windows_2004_Prerelease::ITextDocument4> textDocument4;
reinterpret_cast<IInspectable*>(this->TextDocument)->QueryInterface(IID_PPV_ARGS(&textDocument4));
auto hr = textDocument4->SetMathMode(Windows_2004_Prerelease::RichEditMathMode::MathOnly);
if (FAILED(hr))
{
throw Exception::CreateException(hr);
}
this->LosingFocus += ref new TypedEventHandler<UIElement ^,LosingFocusEventArgs ^>(this, &MathRichEditBox::OnLosingFocus);
this->KeyUp += ref new KeyEventHandler(this, &MathRichEditBox::OnKeyUp);
}
String ^ MathRichEditBox::GetMathTextProperty()
{
// TODO when Windows 10 version 2004 SDK is adopted, replace with:
// String ^ text;
// this->TextDocument->GetMath(&text);
// return text;
ComPtr<Windows_2004_Prerelease::ITextDocument4> textDocument4;
reinterpret_cast<IInspectable*>(this->TextDocument)->QueryInterface(IID_PPV_ARGS(&textDocument4));
HSTRING math;
auto hr = textDocument4->GetMath(&math);
if (FAILED(hr))
{
throw Exception::CreateException(hr);
}
return reinterpret_cast<String ^>(math);
}
void MathRichEditBox::SetMathTextProperty(String ^ newValue)
{
bool readOnlyState = this->IsReadOnly;
this->IsReadOnly = false;
// TODO when Windows 10 version 2004 SDK is adopted, replace with:
// TextDocument->SetMath(newValue);
Microsoft::WRL::ComPtr<Windows_2004_Prerelease::ITextDocument4> textDocument4;
reinterpret_cast<IInspectable*>(this->TextDocument)->QueryInterface(IID_PPV_ARGS(&textDocument4));
auto hr = textDocument4->SetMath(reinterpret_cast<HSTRING>(newValue));
if (FAILED(hr))
{
throw Exception::CreateException(hr);
}
this->IsReadOnly = readOnlyState;
}
void MathRichEditBox::OnLosingFocus(UIElement ^ sender, LosingFocusEventArgs ^ args)
{
if (this->IsReadOnly || this->ContextFlyout->IsOpen)
{
return;
}
SubmitEquation(EquationSubmissionSource::FOCUS_LOST);
}
void MathRichEditBox::OnKeyUp(Object ^ sender, KeyRoutedEventArgs ^ e)
{
if (!this->IsReadOnly && e->Key == VirtualKey::Enter)
{
SubmitEquation(EquationSubmissionSource::ENTER_KEY);
}
}
void MathRichEditBox::OnKeyDown(KeyRoutedEventArgs ^ e)
{
// suppress control + B to prevent bold input from being entered
if ((Window::Current->CoreWindow->GetKeyState(VirtualKey::Control) & CoreVirtualKeyStates::Down) != CoreVirtualKeyStates::Down ||
e->Key != VirtualKey::B)
{
Windows::UI::Xaml::Controls::RichEditBox::OnKeyDown(e);
}
}
void MathRichEditBox::OnMathTextPropertyChanged(Platform::String ^ oldValue, Platform::String ^ newValue)
{
SetMathTextProperty(newValue);
// Get the new math text directly from the TextBox since the textbox may have changed its formatting
SetValue(MathTextProperty, GetMathTextProperty());
}
void MathRichEditBox::InsertText(String ^ text, int cursorOffSet, int selectionLength)
{
// If the rich edit is empty, the math zone may not exist, and so selection (and thus the resulting text) will not be in a math zone.
// If the rich edit has content already, then the mathzone will already be created due to mathonly mode being set and the selection will exist inside the
// math zone. To handle this, we will force a math zone to be created in teh case of the text being empty and then replacing the text inside of the math
// zone with the newly inserted text.
if (GetMathTextProperty() == nullptr)
{
SetMathTextProperty("<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>x</mi></math>");
TextDocument->Selection->StartPosition = 0;
TextDocument->Selection->EndPosition = 1;
}
// insert the text in place of selection
TextDocument->Selection->SetText(Windows::UI::Text::TextSetOptions::FormatRtf, text);
// Move the cursor to the next logical place for users to enter text.
TextDocument->Selection->StartPosition += cursorOffSet;
TextDocument->Selection->EndPosition = TextDocument->Selection->StartPosition + selectionLength;
}
void MathRichEditBox::BackSpace()
{
// if anything is selected, just delete the selection. Note: EndPosition can be before start position.
if (TextDocument->Selection->StartPosition != TextDocument->Selection->EndPosition)
{
TextDocument->Selection->SetText(Windows::UI::Text::TextSetOptions::None, L"");
return;
}
// if we are at the start of the string, do nothing
if (TextDocument->Selection->StartPosition == 0)
{
return;
}
// Select the previous group.
TextDocument->Selection->EndPosition = TextDocument->Selection->StartPosition;
TextDocument->Selection->StartPosition -= 1;
// If the group contains anything complex, we want to give the user a chance to preview the deletion.
// If it's a single character, then just delete it. Otherwise do nothing until the user triggers backspace again.
auto text = TextDocument->Selection->Text;
if (text->Length() == 1)
{
TextDocument->Selection->SetText(Windows::UI::Text::TextSetOptions::None, L"");
}
}
void MathRichEditBox::SubmitEquation(EquationSubmissionSource source)
{
// Clear formatting since the graph control doesn't work with bold/underlines
auto range = this->TextDocument->GetRange(0, this->TextDocument->Selection->EndPosition);
if (range != nullptr)
{
range->CharacterFormat->Underline = UnderlineType::None;
}
auto newVal = GetMathTextProperty();
if (MathText != newVal)
{
// Request the final formatting of the text
auto formatRequest = ref new MathRichEditBoxFormatRequest(newVal);
FormatRequest(this, formatRequest);
if (formatRequest->FormattedText != nullptr && !formatRequest->FormattedText->IsEmpty())
{
newVal = formatRequest->FormattedText;
}
SetValue(MathTextProperty, newVal);
EquationSubmitted(this, ref new MathRichEditBoxSubmission(true, source));
}
else
{
EquationSubmitted(this, ref new MathRichEditBoxSubmission(false, source));
}
}

View File

@@ -0,0 +1,260 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Runtime.InteropServices;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.ApplicationModel;
namespace CalculatorApp
{
namespace Controls
{
namespace Windows_2004_Prerelease
{
public enum RichEditMathMode : int
{
NoMath,
MathOnly
}
[Guid("619c20f2-cb3b-4521-981f-2865b1b93f04")]
interface ITextDocument4
{
int SetMath(string value);
int GetMath(out string value);
int SetMathMode(RichEditMathMode mathMode);
}
}
public enum EquationSubmissionSource
{
FOCUS_LOST,
ENTER_KEY,
PROGRAMMATIC
}
public sealed class MathRichEditBoxSubmission
{
public bool HasTextChanged
{
get => m_HasTextChanged;
}
public EquationSubmissionSource Source
{
get => m_Source;
}
public MathRichEditBoxSubmission(bool hasTextChanged, EquationSubmissionSource source)
{
m_HasTextChanged = hasTextChanged;
m_Source = source;
}
private bool m_HasTextChanged;
private EquationSubmissionSource m_Source;
}
public sealed class MathRichEditBoxFormatRequest
{
public string OriginalText
{
get => m_OriginalText;
}
public string FormattedText
{
get => m_FormattedText;
set => m_FormattedText = value;
}
public MathRichEditBoxFormatRequest(string originalText)
{
m_OriginalText = originalText;
}
private string m_OriginalText;
private string m_FormattedText;
}
public sealed class MathRichEditBox : Windows.UI.Xaml.Controls.RichEditBox
{
public MathRichEditBox()
{
string packageName = Package.Current.Id.Name;
if(packageName == "Microsoft.WindowsCalculator.Dev")
{
LimitedAccessFeatures.TryUnlockFeature(
"com.microsoft.windows.richeditmath",
"BeDD/jxKhz/yfVNA11t4uA==", // Microsoft.WindowsCalculator.Dev
"8wekyb3d8bbwe has registered their use of com.microsoft.windows.richeditmath with Microsoft and agrees to the terms of use.");
}
else if(packageName == "Microsoft.WindowsCalculator")
{
LimitedAccessFeatures.TryUnlockFeature(
"com.microsoft.windows.richeditmath",
"pfanNuxnzo+mAkBQ3N/rGQ==", // Microsoft.WindowsCalculator
"8wekyb3d8bbwe has registered their use of com.microsoft.windows.richeditmath with Microsoft and agrees to the terms of use.");
}
TextDocument.SetMathMode(RichEditMathMode.MathOnly);
LosingFocus += OnLosingFocus;
KeyUp += OnKeyUp;
}
public string MathText
{
get { return (string)GetValue(MathTextProperty); }
set { SetValue(MathTextProperty, value); }
}
// Using a DependencyProperty as the backing store for MathText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MathTextProperty =
DependencyProperty.Register(nameof(MathText), typeof(string), typeof(MathRichEditBox), new PropertyMetadata(string.Empty, (sender, args) =>
{
var self = (MathRichEditBox)sender;
self.OnMathTextPropertyChanged((string)args.OldValue, (string)args.NewValue);
}));
public event EventHandler<MathRichEditBoxFormatRequest> FormatRequest;
public event EventHandler<MathRichEditBoxSubmission> EquationSubmitted;
public void OnMathTextPropertyChanged(string oldValue, string newValue)
{
SetMathTextProperty(newValue);
// Get the new math text directly from the TextBox since the textbox may have changed its formatting
SetValue(MathTextProperty, GetMathTextProperty());
}
public void InsertText(string text, int cursorOffSet, int selectionLength)
{
// If the rich edit is empty, the math zone may not exist, and so selection (and thus the resulting text) will not be in a math zone.
// If the rich edit has content already, then the mathzone will already be created due to mathonly mode being set and the selection will exist inside the
// math zone. To handle this, we will force a math zone to be created in teh case of the text being empty and then replacing the text inside of the math
// zone with the newly inserted text.
if (string.IsNullOrEmpty(GetMathTextProperty()))
{
SetMathTextProperty("<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>x</mi></math>");
TextDocument.Selection.StartPosition = 0;
TextDocument.Selection.EndPosition = 1;
}
// insert the text in place of selection
TextDocument.Selection.SetText(Windows.UI.Text.TextSetOptions.FormatRtf, text);
// Move the cursor to the next logical place for users to enter text.
TextDocument.Selection.StartPosition += cursorOffSet;
TextDocument.Selection.EndPosition = TextDocument.Selection.StartPosition + selectionLength;
}
public void SubmitEquation(EquationSubmissionSource source)
{
// Clear formatting since the graph control doesn't work with bold/underlines
var range = TextDocument.GetRange(0, TextDocument.Selection.EndPosition);
if (range != null)
{
range.CharacterFormat.Underline = UnderlineType.None;
}
var newVal = GetMathTextProperty();
if (MathText != newVal)
{
// Request the final formatting of the text
var formatRequest = new MathRichEditBoxFormatRequest(newVal);
FormatRequest?.Invoke(this, formatRequest);
if (!string.IsNullOrEmpty(formatRequest.FormattedText))
{
newVal = formatRequest.FormattedText;
}
SetValue(MathTextProperty, newVal);
EquationSubmitted?.Invoke(this, new MathRichEditBoxSubmission(true, source));
}
else
{
EquationSubmitted?.Invoke(this, new MathRichEditBoxSubmission(false, source));
}
}
public void BackSpace()
{
// if anything is selected, just delete the selection. Note: EndPosition can be before start position.
if (TextDocument.Selection.StartPosition != TextDocument.Selection.EndPosition)
{
TextDocument.Selection.SetText(Windows.UI.Text.TextSetOptions.None, "");
return;
}
// if we are at the start of the string, do nothing
if (TextDocument.Selection.StartPosition == 0)
{
return;
}
// Select the previous group.
TextDocument.Selection.EndPosition = TextDocument.Selection.StartPosition;
TextDocument.Selection.StartPosition -= 1;
// If the group contains anything complex, we want to give the user a chance to preview the deletion.
// If it's a single character, then just delete it. Otherwise do nothing until the user triggers backspace again.
var text = TextDocument.Selection.Text;
if (text.Length == 1)
{
TextDocument.Selection.SetText(Windows.UI.Text.TextSetOptions.None, "");
}
}
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
// suppress control + B to prevent bold input from being entered
if ((Window.Current.CoreWindow.GetKeyState(VirtualKey.Control) & CoreVirtualKeyStates.Down) != CoreVirtualKeyStates.Down ||
e.Key != VirtualKey.B)
{
base.OnKeyDown(e);
}
}
private string GetMathTextProperty()
{
TextDocument.GetMath(out string math);
return math;
}
private void SetMathTextProperty(string newValue)
{
bool readOnlyState = IsReadOnly;
IsReadOnly = false;
TextDocument.SetMath(newValue);
IsReadOnly = readOnlyState;
}
private void OnLosingFocus(UIElement sender, LosingFocusEventArgs args)
{
if (IsReadOnly || ContextFlyout.IsOpen)
{
return;
}
SubmitEquation(EquationSubmissionSource.FOCUS_LOST);
}
private void OnKeyUp(object sender, KeyRoutedEventArgs e)
{
if (!IsReadOnly && e.Key == VirtualKey.Enter)
{
SubmitEquation(EquationSubmissionSource.ENTER_KEY);
}
}
}
}
}

View File

@@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
enum class EquationSubmissionSource
{
FOCUS_LOST,
ENTER_KEY,
PROGRAMMATIC
};
public
ref class MathRichEditBoxSubmission sealed
{
public:
PROPERTY_R(bool, HasTextChanged);
PROPERTY_R(EquationSubmissionSource, Source);
public:
MathRichEditBoxSubmission(bool hasTextChanged, EquationSubmissionSource source)
: m_HasTextChanged(hasTextChanged)
, m_Source(source)
{
}
};
public
ref class MathRichEditBoxFormatRequest sealed
{
public:
PROPERTY_R(Platform::String^, OriginalText);
PROPERTY_RW(Platform::String ^, FormattedText);
public:
MathRichEditBoxFormatRequest(Platform::String^ originalText)
: m_OriginalText(originalText)
{
}
};
public
ref class MathRichEditBox sealed : Windows::UI::Xaml::Controls::RichEditBox
{
public:
MathRichEditBox();
DEPENDENCY_PROPERTY_OWNER(MathRichEditBox);
DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(Platform::String ^, MathText, L"");
event Windows::Foundation::EventHandler<MathRichEditBoxFormatRequest ^> ^ FormatRequest;
event Windows::Foundation::EventHandler<MathRichEditBoxSubmission^> ^ EquationSubmitted;
void OnMathTextPropertyChanged(Platform::String ^ oldValue, Platform::String ^ newValue);
void InsertText(Platform::String ^ text, int cursorOffSet, int selectionLength);
void SubmitEquation(EquationSubmissionSource source);
void BackSpace();
protected:
void OnKeyDown(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
private:
Platform::String ^ GetMathTextProperty();
void SetMathTextProperty(Platform::String ^ newValue);
void OnLosingFocus(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::LosingFocusEventArgs ^ args);
void OnKeyUp(Platform::Object ^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e);
};
}
}

View File

@@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "OperatorPanelButton.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::ViewManagement;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Media;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, Text);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, Glyph);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, GlyphFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, ChevronFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, FlyoutMenu);
void OperatorPanelButton::OnApplyTemplate()
{
if (FlyoutMenu != nullptr)
{
FlyoutMenu->Closed += ref new EventHandler<Object ^>(this, &OperatorPanelButton::FlyoutClosed);
}
}
void OperatorPanelButton::OnToggle()
{
ToggleButton::OnToggle();
if (IsChecked)
{
FlyoutMenu->ShowAt(this);
}
}
void OperatorPanelButton::FlyoutClosed(Object ^ sender, Object ^ args)
{
IsChecked = false;
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using Windows.Foundation;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using CalculatorApp;
using CalculatorApp.Common;
using CalculatorApp.Controls;
namespace CalculatorApp
{
namespace Controls
{
public sealed class OperatorPanelButton : Windows.UI.Xaml.Controls.Primitives.ToggleButton
{
public OperatorPanelButton()
{
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(string), typeof(OperatorPanelButton), new PropertyMetadata(string.Empty));
public string Glyph
{
get { return (string)GetValue(GlyphProperty); }
set { SetValue(GlyphProperty, value); }
}
// Using a DependencyProperty as the backing store for Glyph. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GlyphProperty =
DependencyProperty.Register(nameof(Glyph), typeof(string), typeof(OperatorPanelButton), new PropertyMetadata(string.Empty));
public double GlyphFontSize
{
get { return (double)GetValue(GlyphFontSizeProperty); }
set { SetValue(GlyphFontSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for GlyphFontSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GlyphFontSizeProperty =
DependencyProperty.Register(nameof(GlyphFontSize), typeof(double), typeof(OperatorPanelButton), new PropertyMetadata(default(double)));
public double ChevronFontSize
{
get { return (double)GetValue(ChevronFontSizeProperty); }
set { SetValue(ChevronFontSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for ChevronFontSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ChevronFontSizeProperty =
DependencyProperty.Register(nameof(ChevronFontSize), typeof(double), typeof(OperatorPanelButton), new PropertyMetadata(default(double)));
public Flyout FlyoutMenu
{
get { return (Flyout)GetValue(FlyoutMenuProperty); }
set { SetValue(FlyoutMenuProperty, value); }
}
// Using a DependencyProperty as the backing store for FlyoutMenu. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FlyoutMenuProperty =
DependencyProperty.Register(nameof(FlyoutMenu), typeof(Flyout), typeof(OperatorPanelButton), new PropertyMetadata(default(Flyout)));
protected override void OnApplyTemplate()
{
if (FlyoutMenu != null)
{
FlyoutMenu.Closed += FlyoutClosed;
}
}
protected override void OnToggle()
{
base.OnToggle();
if (IsChecked == true)
{
FlyoutMenu.ShowAt(this);
}
}
private void FlyoutClosed(object sender, object args)
{
IsChecked = false;
}
}
}
}

View File

@@ -1,36 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class OperatorPanelButton sealed : Windows::UI::Xaml::Controls::Primitives::ToggleButton
{
public:
OperatorPanelButton()
{
}
DEPENDENCY_PROPERTY_OWNER(OperatorPanelButton);
DEPENDENCY_PROPERTY(Platform::String^, Text);
DEPENDENCY_PROPERTY(Platform::String^, Glyph);
DEPENDENCY_PROPERTY(double, GlyphFontSize);
DEPENDENCY_PROPERTY(double, ChevronFontSize);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::Flyout^, FlyoutMenu);
protected:
virtual void OnApplyTemplate() override;
virtual void OnToggle() override;
private:
void FlyoutClosed(Platform::Object^ sender, Platform::Object^ args);
};
}
}

View File

@@ -1,147 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "OperatorPanelListView.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Controls;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Controls;
OperatorPanelListView::OperatorPanelListView()
{
}
void OperatorPanelListView::OnApplyTemplate()
{
m_scrollViewer = dynamic_cast<ScrollViewer^>(GetTemplateChild("ScrollViewer"));
m_scrollLeft = dynamic_cast<Button^>(GetTemplateChild("ScrollLeft"));
m_scrollRight = dynamic_cast<Button^>(GetTemplateChild("ScrollRight"));
m_content = dynamic_cast<ItemsPresenter^>(GetTemplateChild("Content"));
if (m_scrollLeft != nullptr)
{
m_scrollLeft->Click += ref new RoutedEventHandler(this, &OperatorPanelListView::OnScrollClick);
m_scrollLeft->PointerExited += ref new PointerEventHandler(this, &OperatorPanelListView::OnButtonPointerExited);
}
if (m_scrollRight != nullptr)
{
m_scrollRight->Click += ref new RoutedEventHandler(this, &OperatorPanelListView::OnScrollClick);
m_scrollRight->PointerExited += ref new PointerEventHandler(this, &OperatorPanelListView::OnButtonPointerExited);
}
if (m_scrollViewer != nullptr)
{
m_scrollViewer->ViewChanged += ref new EventHandler<ScrollViewerViewChangedEventArgs^>(this, &OperatorPanelListView::ScrollViewChanged);
}
this->PointerEntered += ref new PointerEventHandler(this, &OperatorPanelListView::OnPointerEntered);
this->PointerExited += ref new PointerEventHandler(this, &OperatorPanelListView::OnPointerExited);
ListView::OnApplyTemplate();
}
void OperatorPanelListView::ScrollViewChanged(_In_ Object^, _In_ ScrollViewerViewChangedEventArgs^ e)
{
if (m_isPointerEntered && !e->IsIntermediate)
{
UpdateScrollButtons();
}
}
void OperatorPanelListView::OnScrollClick(_In_ Object^ sender, _In_ RoutedEventArgs^)
{
auto clicked = dynamic_cast<Button^>(sender);
if (clicked == m_scrollLeft)
{
ScrollLeft();
}
else
{
ScrollRight();
}
}
void OperatorPanelListView::OnButtonPointerExited(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
auto button = dynamic_cast<Button^>(sender);
// Do not bubble up the pointer exit event to the control if the button being exited was not visible
if (button->Visibility == ::Visibility::Collapsed)
{
e->Handled = true;
}
}
void OperatorPanelListView::OnPointerEntered(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse)
{
UpdateScrollButtons();
m_isPointerEntered = true;
}
}
void OperatorPanelListView::OnPointerExited(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
m_scrollLeft->Visibility = ::Visibility::Collapsed;
m_scrollRight->Visibility = ::Visibility::Collapsed;
m_isPointerEntered = false;
}
void OperatorPanelListView::ScrollLeft()
{
double offset = m_scrollViewer->HorizontalOffset - (scrollRatio * m_scrollViewer->ViewportWidth);
m_scrollViewer->ChangeView(offset, nullptr, nullptr);
}
void OperatorPanelListView::ScrollRight()
{
double offset = m_scrollViewer->HorizontalOffset + (scrollRatio * m_scrollViewer->ViewportWidth);
m_scrollViewer->ChangeView(offset, nullptr, nullptr);
}
void OperatorPanelListView::UpdateScrollButtons()
{
if (m_content == nullptr || m_scrollViewer == nullptr)
{
return;
}
// When the width is smaller than the container, don't show any
if (m_content->ActualWidth <= m_scrollViewer->ActualWidth)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
}
// We have more number on both side. Show both arrows
else if ((m_scrollViewer->HorizontalOffset > 0) && (m_scrollViewer->HorizontalOffset < (m_scrollViewer->ExtentWidth - m_scrollViewer->ViewportWidth)))
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Visible);
}
// Width is larger than the container and left most part of the number is shown. Should be able to scroll left.
else if (m_scrollViewer->HorizontalOffset == 0)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Visible);
}
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Collapsed);
}
}
void OperatorPanelListView::ShowHideScrollButtons(::Visibility vLeft, ::Visibility vRight)
{
if (m_scrollLeft != nullptr && m_scrollRight != nullptr)
{
m_scrollLeft->Visibility = vLeft;
m_scrollRight->Visibility = vRight;
}
}

View File

@@ -0,0 +1,164 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using CalculatorApp;
using CalculatorApp.Controls;
using Windows.Foundation;
using Windows.Devices.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Controls;
namespace CalculatorApp
{
namespace Controls
{
public sealed class OperatorPanelListView : Windows.UI.Xaml.Controls.ListView
{
public OperatorPanelListView()
{
}
protected override void OnApplyTemplate()
{
m_scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
m_scrollLeft = GetTemplateChild("ScrollLeft") as Button;
m_scrollRight = GetTemplateChild("ScrollRight") as Button;
m_content = GetTemplateChild("Content") as ItemsPresenter;
if (m_scrollLeft != null)
{
m_scrollLeft.Click += OnScrollClick;
m_scrollLeft.PointerExited += OnButtonPointerExited;
}
if (m_scrollRight != null)
{
m_scrollRight.Click += OnScrollClick;
m_scrollRight.PointerExited += OnButtonPointerExited;
}
if (m_scrollViewer != null)
{
m_scrollViewer.ViewChanged += ScrollViewChanged;
}
this.PointerEntered += OnPointerEntered;
this.PointerExited += OnPointerExited;
base.OnApplyTemplate();
}
private void OnScrollClick(object sender, RoutedEventArgs e)
{
var clicked = sender as Button;
if (clicked == m_scrollLeft)
{
ScrollLeft();
}
else
{
ScrollRight();
}
}
private void OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
{
UpdateScrollButtons();
m_isPointerEntered = true;
}
}
private void OnPointerExited(object sender, PointerRoutedEventArgs e)
{
m_scrollLeft.Visibility = Visibility.Collapsed;
m_scrollRight.Visibility = Visibility.Collapsed;
m_isPointerEntered = false;
}
private void OnButtonPointerExited(object sender, PointerRoutedEventArgs e)
{
var button = sender as Button;
// Do not bubble up the pointer exit event to the control if the button being exited was not visible
if (button.Visibility == Visibility.Collapsed)
{
e.Handled = true;
}
}
private void ScrollViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (m_isPointerEntered && !e.IsIntermediate)
{
UpdateScrollButtons();
}
}
private void ShowHideScrollButtons(Visibility vLeft, Visibility vRight)
{
if (m_scrollLeft != null && m_scrollRight != null)
{
m_scrollLeft.Visibility = vLeft;
m_scrollRight.Visibility = vRight;
}
}
private void UpdateScrollButtons()
{
if (m_content == null || m_scrollViewer == null)
{
return;
}
// When the width is smaller than the container, don't show any
if (m_content.ActualWidth <= m_scrollViewer.ActualWidth)
{
ShowHideScrollButtons(Visibility.Collapsed, Visibility.Collapsed);
}
// We have more number on both side. Show both arrows
else if ((m_scrollViewer.HorizontalOffset > 0) && (m_scrollViewer.HorizontalOffset < (m_scrollViewer.ExtentWidth - m_scrollViewer.ViewportWidth)))
{
ShowHideScrollButtons(Visibility.Visible, Visibility.Visible);
}
// Width is larger than the container and left most part of the number is shown. Should be able to scroll left.
else if (m_scrollViewer.HorizontalOffset == 0)
{
ShowHideScrollButtons(Visibility.Collapsed, Visibility.Visible);
}
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
{
ShowHideScrollButtons(Visibility.Visible, Visibility.Collapsed);
}
}
private void ScrollLeft()
{
double offset = m_scrollViewer.HorizontalOffset - (scrollRatio * m_scrollViewer.ViewportWidth);
m_scrollViewer.ChangeView(offset, null, null);
}
private void ScrollRight()
{
double offset = m_scrollViewer.HorizontalOffset + (scrollRatio * m_scrollViewer.ViewportWidth);
m_scrollViewer.ChangeView(offset, null, null);
}
private double scrollRatio = 0.7;
private bool m_isPointerEntered;
private Windows.UI.Xaml.Controls.ItemsPresenter m_content;
private Windows.UI.Xaml.Controls.ScrollViewer m_scrollViewer;
private Windows.UI.Xaml.Controls.Button m_scrollLeft;
private Windows.UI.Xaml.Controls.Button m_scrollRight;
}
}
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class OperatorPanelListView sealed : public Windows::UI::Xaml::Controls::ListView
{
public:
OperatorPanelListView();
protected:
virtual void OnApplyTemplate() override;
private:
void OnScrollClick(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs^ e);
void OnPointerEntered(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void OnPointerExited(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void OnButtonPointerExited(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void ScrollViewChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs^ args);
void ShowHideScrollButtons(Windows::UI::Xaml::Visibility vLeft, Windows::UI::Xaml::Visibility vRight);
void UpdateScrollButtons();
void ScrollLeft();
void ScrollRight();
double scrollRatio = 0.7;
bool m_isPointerEntered;
Windows::UI::Xaml::Controls::ItemsPresenter^ m_content;
Windows::UI::Xaml::Controls::ScrollViewer^ m_scrollViewer;
Windows::UI::Xaml::Controls::Button^ m_scrollLeft;
Windows::UI::Xaml::Controls::Button^ m_scrollRight;
};
}
}

View File

@@ -1,240 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "OverflowTextBlock.h"
#include "OverflowTextBlockAutomationPeer.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Devices::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, IsActive);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TextStyle);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TokensUpdated);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsWidth);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsPlacement);
static constexpr unsigned int SCROLL_BUTTONS_APPROXIMATION_RANGE = 4;
static constexpr double SCROLL_RATIO = 0.7;
void OverflowTextBlock::OnApplyTemplate()
{
UnregisterEventHandlers();
auto uiElement = GetTemplateChild("ExpressionContainer");
if (uiElement != nullptr)
{
m_expressionContainer = safe_cast<ScrollViewer ^>(uiElement);
m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr);
m_containerViewChangedToken = m_expressionContainer->ViewChanged +=
ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
}
uiElement = GetTemplateChild("ExpressionContent");
if (uiElement != nullptr)
{
m_expressionContent = safe_cast<FrameworkElement ^>(uiElement);
}
uiElement = GetTemplateChild("ScrollLeft");
if (uiElement != nullptr)
{
m_scrollLeft = safe_cast<Button ^>(uiElement);
m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollLeftClick);
}
uiElement = GetTemplateChild("ScrollRight");
if (uiElement != nullptr)
{
m_scrollRight = safe_cast<Button ^>(uiElement);
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollRightClick);
}
uiElement = GetTemplateChild("TokenList");
if (uiElement != nullptr)
{
m_itemsControl = safe_cast<ItemsControl ^>(uiElement);
}
UpdateAllState();
}
AutomationPeer ^ OverflowTextBlock::OnCreateAutomationPeer()
{
return ref new OverflowTextBlockAutomationPeer(this);
}
void OverflowTextBlock::OnTokensUpdatedPropertyChanged(bool /*oldValue*/, bool newValue)
{
if (m_expressionContainer != nullptr && newValue)
{
m_expressionContainer->UpdateLayout();
m_expressionContainer->ChangeView(m_expressionContainer->ScrollableWidth, nullptr, nullptr, true);
}
auto newIsAccessibilityViewControl = m_itemsControl != nullptr && m_itemsControl->Items->Size > 0;
if (m_isAccessibilityViewControl != newIsAccessibilityViewControl)
{
m_isAccessibilityViewControl = newIsAccessibilityViewControl;
AutomationProperties::SetAccessibilityView(this, newIsAccessibilityViewControl ? AccessibilityView::Control : AccessibilityView::Raw);
}
UpdateScrollButtons();
}
void OverflowTextBlock::UpdateAllState()
{
UpdateVisualState();
}
void OverflowTextBlock::UpdateVisualState()
{
if (IsActive)
{
VisualStateManager::GoToState(this, "Active", true);
}
else
{
VisualStateManager::GoToState(this, "Normal", true);
}
}
void OverflowTextBlock::ScrollLeft()
{
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset > 0)
{
double offset = m_expressionContainer->HorizontalOffset - (SCROLL_RATIO * m_expressionContainer->ViewportWidth);
m_expressionContainer->ChangeView(offset, nullptr, nullptr);
m_expressionContainer->UpdateLayout();
UpdateScrollButtons();
}
}
void OverflowTextBlock::ScrollRight()
{
auto realOffset = m_expressionContainer->HorizontalOffset + m_expressionContainer->Padding.Left + m_expressionContent->Margin.Left;
if (m_expressionContainer != nullptr && realOffset + m_expressionContainer->ActualWidth < m_expressionContent->ActualWidth)
{
double offset = m_expressionContainer->HorizontalOffset + (SCROLL_RATIO * m_expressionContainer->ViewportWidth);
m_expressionContainer->ChangeView(offset, nullptr, nullptr);
m_expressionContainer->UpdateLayout();
UpdateScrollButtons();
}
}
void OverflowTextBlock::OnScrollLeftClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
{
ScrollLeft();
}
void OverflowTextBlock::OnScrollRightClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
{
ScrollRight();
}
void OverflowTextBlock::UpdateScrollButtons()
{
if (m_expressionContainer == nullptr || m_scrollLeft == nullptr || m_scrollRight == nullptr)
{
return;
}
auto realOffset = m_expressionContainer->HorizontalOffset + m_expressionContainer->Padding.Left + m_expressionContent->Margin.Left;
auto scrollLeftVisibility = realOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? ::Visibility::Visible : ::Visibility::Collapsed;
auto scrollRightVisibility = realOffset + m_expressionContainer->ActualWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_expressionContent->ActualWidth
? ::Visibility::Visible
: ::Visibility::Collapsed;
bool shouldTryFocusScrollRight = false;
if (m_scrollLeft->Visibility != scrollLeftVisibility)
{
if (scrollLeftVisibility == ::Visibility::Collapsed)
{
shouldTryFocusScrollRight = m_scrollLeft->Equals(FocusManager::GetFocusedElement());
}
m_scrollLeft->Visibility = scrollLeftVisibility;
}
if (m_scrollRight->Visibility != scrollRightVisibility)
{
if (scrollRightVisibility == ::Visibility::Collapsed && m_scrollLeft->Visibility == ::Visibility::Visible
&& m_scrollRight->Equals(FocusManager::GetFocusedElement()))
{
m_scrollLeft->Focus(::FocusState::Programmatic);
}
m_scrollRight->Visibility = scrollRightVisibility;
}
if (shouldTryFocusScrollRight && scrollRightVisibility == ::Visibility::Visible)
{
m_scrollRight->Focus(::FocusState::Programmatic);
}
if (ScrollButtonsPlacement == OverflowButtonPlacement::Above && m_expressionContent != nullptr)
{
double left = m_scrollLeft != nullptr && m_scrollLeft->Visibility == ::Visibility::Visible ? ScrollButtonsWidth : 0;
double right = m_scrollRight != nullptr && m_scrollRight->Visibility == ::Visibility::Visible ? ScrollButtonsWidth : 0;
if (m_expressionContainer->Padding.Left != left || m_expressionContainer->Padding.Right != right)
{
m_expressionContainer->ViewChanged -= m_containerViewChangedToken;
m_expressionContainer->Padding = Thickness(left, 0, right, 0);
m_expressionContent->Margin = Thickness(-left, 0, -right, 0);
m_expressionContainer->UpdateLayout();
m_expressionContainer->Measure(m_expressionContainer->RenderSize);
m_containerViewChangedToken = m_expressionContainer->ViewChanged +=
ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
}
}
}
void OverflowTextBlock::UnregisterEventHandlers()
{
// Unregister the event handlers
if (m_scrollLeft != nullptr)
{
m_scrollLeft->Click -= m_scrollLeftClickEventToken;
}
if (m_scrollRight != nullptr)
{
m_scrollRight->Click -= m_scrollRightClickEventToken;
}
if (m_expressionContainer != nullptr)
{
m_expressionContainer->ViewChanged -= m_containerViewChangedToken;
}
}
void OverflowTextBlock::OnViewChanged(_In_opt_ Object ^ /*sender*/, _In_opt_ ScrollViewerViewChangedEventArgs ^ /*args*/)
{
UpdateScrollButtons();
}
void OverflowTextBlock::OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement /*oldValue*/, OverflowButtonPlacement newValue)
{
if (newValue == OverflowButtonPlacement::InLine)
{
m_expressionContainer->Padding = Thickness(0);
m_expressionContent->Margin = Thickness(0);
}
UpdateScrollButtons();
}

View File

@@ -0,0 +1,332 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using CalculatorApp;
using CalculatorApp.Common;
using CalculatorApp.Controls;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Devices.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.ApplicationModel.Store;
namespace CalculatorApp
{
namespace Controls
{
public enum OverflowButtonPlacement : int
{
InLine,
Above
};
public sealed class OverflowTextBlock : Windows.UI.Xaml.Controls.Control
{
public OverflowTextBlock()
{
m_isAccessibilityViewControl = false;
m_expressionContent = null;
m_itemsControl = null;
m_expressionContainer = null;
m_scrollLeft = null;
m_scrollRight = null;
}
public bool TokensUpdated
{
get { return (bool)GetValue(TokensUpdatedProperty); }
set { SetValue(TokensUpdatedProperty, value); }
}
// Using a DependencyProperty as the backing store for TokensUpdated. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TokensUpdatedProperty =
DependencyProperty.Register(nameof(TokensUpdated), typeof(bool), typeof(OverflowTextBlock), new PropertyMetadata(default(bool), new PropertyChangedCallback((sender, args) =>
{
var self = (OverflowTextBlock)sender;
self.OnTokensUpdatedPropertyChanged((bool)args.OldValue, (bool)args.NewValue);
})));
public OverflowButtonPlacement ScrollButtonsPlacement
{
get { return (OverflowButtonPlacement)GetValue(ScrollButtonsPlacementProperty); }
set { SetValue(ScrollButtonsPlacementProperty, value); }
}
// Using a DependencyProperty as the backing store for ScrollButtonsPlacement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScrollButtonsPlacementProperty =
DependencyProperty.Register(nameof(ScrollButtonsPlacement), typeof(OverflowButtonPlacement), typeof(OverflowTextBlock), new PropertyMetadata(default(OverflowButtonPlacement), new PropertyChangedCallback((sender, args) =>
{
var self = (OverflowTextBlock)sender;
self.OnScrollButtonsPlacementPropertyChanged((OverflowButtonPlacement)args.OldValue, (OverflowButtonPlacement)args.NewValue);
})));
public bool IsActive
{
get { return (bool)GetValue(IsActiveProperty); }
set { SetValue(IsActiveProperty, value); }
}
// Using a DependencyProperty as the backing store for IsActive. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register(nameof(IsActive), typeof(bool), typeof(OverflowTextBlock), new PropertyMetadata(default(bool)));
public Windows.UI.Xaml.Style TextStyle
{
get { return (Style)GetValue(TextStyleProperty); }
set { SetValue(TextStyleProperty, value); }
}
// Using a DependencyProperty as the backing store for TextStyle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextStyleProperty =
DependencyProperty.Register(nameof(TextStyle), typeof(Style), typeof(OverflowTextBlock), new PropertyMetadata(default(Style)));
public double ScrollButtonsWidth
{
get { return (double)GetValue(ScrollButtonsWidthProperty); }
set { SetValue(ScrollButtonsWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for ScrollButtonsWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScrollButtonsWidthProperty =
DependencyProperty.Register(nameof(ScrollButtonsWidth), typeof(double), typeof(OverflowTextBlock), new PropertyMetadata(default(double)));
public double ScrollButtonsFontSize
{
get { return (double)GetValue(ScrollButtonsFontSizeProperty); }
set { SetValue(ScrollButtonsFontSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for ScrollButtonsFontSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScrollButtonsFontSizeProperty =
DependencyProperty.Register(nameof(ScrollButtonsFontSize), typeof(double), typeof(OverflowTextBlock), new PropertyMetadata(default(double)));
public void OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue)
{
if (m_expressionContainer != null && newValue)
{
m_expressionContainer.UpdateLayout();
m_expressionContainer.ChangeView(m_expressionContainer.ScrollableWidth, null, null, true);
}
var newIsAccessibilityViewControl = m_itemsControl != null && m_itemsControl.Items.Count > 0;
if (m_isAccessibilityViewControl != newIsAccessibilityViewControl)
{
m_isAccessibilityViewControl = newIsAccessibilityViewControl;
AutomationProperties.SetAccessibilityView(this, newIsAccessibilityViewControl ? AccessibilityView.Control : AccessibilityView.Raw);
}
UpdateScrollButtons();
}
public void OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement oldValue, OverflowButtonPlacement newValue)
{
if (newValue == OverflowButtonPlacement.InLine)
{
m_expressionContainer.Padding = new Thickness(0);
m_expressionContent.Margin = new Thickness(0);
}
UpdateScrollButtons();
}
public void UpdateScrollButtons()
{
if (m_expressionContainer == null || m_scrollLeft == null || m_scrollRight == null)
{
return;
}
var realOffset = m_expressionContainer.HorizontalOffset + m_expressionContainer.Padding.Left + m_expressionContent.Margin.Left;
var scrollLeftVisibility = realOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? Visibility.Visible : Visibility.Collapsed;
var scrollRightVisibility = realOffset + m_expressionContainer.ActualWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_expressionContent.ActualWidth
? Visibility.Visible
: Visibility.Collapsed;
bool shouldTryFocusScrollRight = false;
if (m_scrollLeft.Visibility != scrollLeftVisibility)
{
if (scrollLeftVisibility == Visibility.Collapsed)
{
shouldTryFocusScrollRight = m_scrollLeft.Equals(FocusManager.GetFocusedElement());
}
m_scrollLeft.Visibility = scrollLeftVisibility;
}
if (m_scrollRight.Visibility != scrollRightVisibility)
{
if (scrollRightVisibility == Visibility.Collapsed && m_scrollLeft.Visibility == Visibility.Visible
&& m_scrollRight.Equals(FocusManager.GetFocusedElement()))
{
m_scrollLeft.Focus(FocusState.Programmatic);
}
m_scrollRight.Visibility = scrollRightVisibility;
}
if (shouldTryFocusScrollRight && scrollRightVisibility == Visibility.Visible)
{
m_scrollRight.Focus(FocusState.Programmatic);
}
if (ScrollButtonsPlacement == OverflowButtonPlacement.Above && m_expressionContent != null)
{
double left = m_scrollLeft != null && m_scrollLeft.Visibility == Visibility.Visible ? ScrollButtonsWidth : 0;
double right = m_scrollRight != null && m_scrollRight.Visibility == Visibility.Visible ? ScrollButtonsWidth : 0;
if (m_expressionContainer.Padding.Left != left || m_expressionContainer.Padding.Right != right)
{
m_expressionContainer.ViewChanged -= OnViewChanged;
m_expressionContainer.Padding = new Thickness(left, 0, right, 0);
m_expressionContent.Margin = new Thickness(-left, 0, -right, 0);
m_expressionContainer.UpdateLayout();
m_expressionContainer.Measure(m_expressionContainer.RenderSize);
m_expressionContainer.ViewChanged += OnViewChanged;
}
}
}
public void UnregisterEventHandlers()
{
// Unregister the event handlers
if (m_scrollLeft != null)
{
m_scrollLeft.Click -= OnScrollLeftClick;
}
if (m_scrollRight != null)
{
m_scrollRight.Click -= OnScrollRightClick;
}
if (m_expressionContainer != null)
{
m_expressionContainer.ViewChanged -= OnViewChanged;
}
}
protected override void OnApplyTemplate()
{
UnregisterEventHandlers();
var uiElement = GetTemplateChild("ExpressionContainer");
if (uiElement != null)
{
m_expressionContainer = (ScrollViewer)uiElement;
m_expressionContainer.ChangeView(m_expressionContainer.ExtentWidth - m_expressionContainer.ViewportWidth, null, null);
m_expressionContainer.ViewChanged += OnViewChanged;
}
uiElement = GetTemplateChild("ExpressionContent");
if (uiElement != null)
{
m_expressionContent = (FrameworkElement)uiElement;
}
uiElement = GetTemplateChild("ScrollLeft");
if (uiElement != null)
{
m_scrollLeft = (Button)uiElement;
m_scrollLeft.Click += OnScrollLeftClick;
}
uiElement = GetTemplateChild("ScrollRight");
if (uiElement != null)
{
m_scrollRight = (Button)uiElement;
m_scrollRight.Click += OnScrollRightClick;
}
uiElement = GetTemplateChild("TokenList");
if (uiElement != null)
{
m_itemsControl = (ItemsControl)uiElement;
}
UpdateAllState();
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new OverflowTextBlockAutomationPeer(this);
}
private void OnScrollLeftClick(object sender, RoutedEventArgs e)
{
ScrollLeft();
}
private void OnScrollRightClick(object sender, RoutedEventArgs e)
{
ScrollRight();
}
private void OnViewChanged(object sender, ScrollViewerViewChangedEventArgs args)
{
UpdateScrollButtons();
}
private void UpdateVisualState()
{
if (IsActive)
{
VisualStateManager.GoToState(this, "Active", true);
}
else
{
VisualStateManager.GoToState(this, "Normal", true);
}
}
private void UpdateAllState()
{
UpdateVisualState();
}
private void ScrollLeft()
{
if (m_expressionContainer != null && m_expressionContainer.HorizontalOffset > 0)
{
double offset = m_expressionContainer.HorizontalOffset - (SCROLL_RATIO * m_expressionContainer.ViewportWidth);
m_expressionContainer.ChangeView(offset, null, null);
m_expressionContainer.UpdateLayout();
UpdateScrollButtons();
}
}
private void ScrollRight()
{
var realOffset = m_expressionContainer.HorizontalOffset + m_expressionContainer.Padding.Left + m_expressionContent.Margin.Left;
if (m_expressionContainer != null && realOffset + m_expressionContainer.ActualWidth < m_expressionContent.ActualWidth)
{
double offset = m_expressionContainer.HorizontalOffset + (SCROLL_RATIO * m_expressionContainer.ViewportWidth);
m_expressionContainer.ChangeView(offset, null, null);
m_expressionContainer.UpdateLayout();
UpdateScrollButtons();
}
}
private const uint SCROLL_BUTTONS_APPROXIMATION_RANGE = 4;
private const double SCROLL_RATIO = 0.7;
private bool m_isAccessibilityViewControl;
private Windows.UI.Xaml.FrameworkElement m_expressionContent;
private Windows.UI.Xaml.Controls.ItemsControl m_itemsControl;
private Windows.UI.Xaml.Controls.ScrollViewer m_expressionContainer;
private Windows.UI.Xaml.Controls.Button m_scrollLeft;
private Windows.UI.Xaml.Controls.Button m_scrollRight;
}
}
}

View File

@@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
enum class OverflowButtonPlacement : int
{
InLine,
Above
};
public
ref class OverflowTextBlock sealed : public Windows::UI::Xaml::Controls::Control
{
public:
OverflowTextBlock()
: m_isAccessibilityViewControl(false)
, m_ignoreViewChanged(false)
, m_expressionContent(nullptr)
, m_itemsControl(nullptr)
, m_expressionContainer(nullptr)
, m_scrollLeft(nullptr)
, m_scrollRight(nullptr)
{
}
DEPENDENCY_PROPERTY_OWNER(OverflowTextBlock);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, TokensUpdated);
DEPENDENCY_PROPERTY_WITH_CALLBACK(OverflowButtonPlacement, ScrollButtonsPlacement);
DEPENDENCY_PROPERTY(bool, IsActive);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Style ^, TextStyle);
DEPENDENCY_PROPERTY(double, ScrollButtonsWidth);
DEPENDENCY_PROPERTY(double, ScrollButtonsFontSize);
void OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue);
void OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement oldValue, OverflowButtonPlacement newValue);
void UpdateScrollButtons();
void UnregisterEventHandlers();
protected:
virtual void OnApplyTemplate() override;
virtual Windows::UI::Xaml::Automation::Peers::AutomationPeer ^ OnCreateAutomationPeer() override;
private:
void OnScrollLeftClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnScrollRightClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnViewChanged(_In_opt_ Platform::Object ^ sender, _In_opt_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^ args);
void UpdateVisualState();
void UpdateAllState();
void ScrollLeft();
void ScrollRight();
bool m_isAccessibilityViewControl;
bool m_ignoreViewChanged;
Windows::UI::Xaml::FrameworkElement ^ m_expressionContent;
Windows::UI::Xaml::Controls::ItemsControl ^ m_itemsControl;
Windows::UI::Xaml::Controls::ScrollViewer ^ m_expressionContainer;
Windows::UI::Xaml::Controls::Button ^ m_scrollLeft;
Windows::UI::Xaml::Controls::Button ^ m_scrollRight;
Windows::Foundation::EventRegistrationToken m_scrollLeftClickEventToken;
Windows::Foundation::EventRegistrationToken m_scrollRightClickEventToken;
Windows::Foundation::EventRegistrationToken m_containerViewChangedToken;
};
}
}

View File

@@ -1,27 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "Controls/OverflowTextBlock.h"
#include "OverflowTextBlockAutomationPeer.h"
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace Windows::Foundation::Collections;
namespace CalculatorApp::Controls
{
OverflowTextBlockAutomationPeer::OverflowTextBlockAutomationPeer(OverflowTextBlock ^ owner)
: FrameworkElementAutomationPeer(owner)
{
}
AutomationControlType OverflowTextBlockAutomationPeer::GetAutomationControlTypeCore()
{
return AutomationControlType::Text;
}
IVector<AutomationPeer ^> ^ OverflowTextBlockAutomationPeer::GetChildrenCore()
{
return nullptr;
}
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using Windows.UI.Xaml.Automation.Peers;
using Windows.Foundation.Collections;
namespace CalculatorApp
{
namespace Controls
{
public sealed class OverflowTextBlockAutomationPeer : Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer
{
public OverflowTextBlockAutomationPeer(OverflowTextBlock owner) : base(owner)
{
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Text;
}
protected override IList<AutomationPeer> GetChildrenCore()
{
return null;
}
}
}
}

View File

@@ -1,22 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "Controls/OverflowTextBlock.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class OverflowTextBlockAutomationPeer sealed : Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer
{
public:
OverflowTextBlockAutomationPeer(OverflowTextBlock ^ owner);
virtual Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() override;
virtual Windows::Foundation::Collections::IVector<Windows::UI::Xaml::Automation::Peers::AutomationPeer ^> ^ GetChildrenCore() override;
};
}
}

View File

@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "RadixButton.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation::Collections;
using namespace Windows::System;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Data;
String ^ RadixButton::GetRawDisplayValue()
{
String ^ radixContent = Content->ToString();
return LocalizationSettings::GetInstance().RemoveGroupSeparators(radixContent);
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
namespace CalculatorApp
{
namespace Controls
{
public sealed class RadixButton : Windows.UI.Xaml.Controls.RadioButton
{
public RadixButton()
{ }
internal string GetRawDisplayValue()
{
string radixContent = Content.ToString();
return LocalizationSettings.GetInstance().RemoveGroupSeparators(radixContent);
}
}
}
}

View File

@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Controls
{
public
ref class RadixButton sealed : public Windows::UI::Xaml::Controls::RadioButton
{
public:
RadixButton(){};
internal : Platform::String ^ GetRawDisplayValue();
};
}
}

View File

@@ -1,40 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "SupplementaryItemsControl.h"
#include "CalcViewModel/UnitConverterViewModel.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Controls;
using namespace CalculatorApp::ViewModel;
using namespace Windows::System;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace Platform;
using namespace Windows::Foundation::Collections;
using namespace std;
DependencyObject ^ SupplementaryItemsControl::GetContainerForItemOverride()
{
return ref new SupplementaryContentPresenter();
}
void SupplementaryItemsControl::PrepareContainerForItemOverride(DependencyObject ^ element, Object ^ item)
{
ItemsControl::PrepareContainerForItemOverride(element, item);
auto supplementaryResult = dynamic_cast<SupplementaryResult ^>(item);
if (supplementaryResult)
{
AutomationProperties::SetName(element, supplementaryResult->GetLocalizedAutomationName());
}
}
AutomationPeer ^ SupplementaryContentPresenter::OnCreateAutomationPeer()
{
return ref new SupplementaryContentPresenterAP(this);
}

View File

@@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using CalculatorApp;
using CalculatorApp.Controls;
using CalculatorApp.ViewModel;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.Foundation.Collections;
namespace CalculatorApp
{
namespace Controls
{
public sealed class SupplementaryItemsControl : ItemsControl
{
public SupplementaryItemsControl()
{
}
protected override DependencyObject GetContainerForItemOverride()
{
return new SupplementaryContentPresenter();
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var supplementaryResult = item as SupplementaryResult;
if (supplementaryResult != null)
{
AutomationProperties.SetName(element, supplementaryResult.GetLocalizedAutomationName());
}
}
}
public sealed class SupplementaryContentPresenter : ContentPresenter
{
public SupplementaryContentPresenter()
{
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new SupplementaryContentPresenterAP(this);
}
}
sealed class SupplementaryContentPresenterAP : FrameworkElementAutomationPeer
{
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Text;
}
protected override IList<AutomationPeer> GetChildrenCore()
{
return null;
}
internal SupplementaryContentPresenterAP(SupplementaryContentPresenter owner)
: base(owner)
{
}
}
}
}

View File

@@ -1,54 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Controls
{
public
ref class SupplementaryItemsControl sealed : public Windows::UI::Xaml::Controls::ItemsControl
{
public:
SupplementaryItemsControl()
{
}
protected:
virtual Windows::UI::Xaml::DependencyObject ^ GetContainerForItemOverride() override;
virtual void PrepareContainerForItemOverride(Windows::UI::Xaml::DependencyObject ^ element, Platform::Object ^ item) override;
};
public
ref class SupplementaryContentPresenter sealed : public Windows::UI::Xaml::Controls::ContentPresenter
{
public:
SupplementaryContentPresenter()
{
}
protected:
virtual Windows::UI::Xaml::Automation::Peers::AutomationPeer ^ OnCreateAutomationPeer() override;
};
ref class SupplementaryContentPresenterAP sealed : public Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer
{
protected:
virtual Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() override
{
return Windows::UI::Xaml::Automation::Peers::AutomationControlType::Text;
}
virtual Windows::Foundation::Collections::IVector<Windows::UI::Xaml::Automation::Peers::AutomationPeer ^> ^ GetChildrenCore() override
{
return nullptr;
}
internal : SupplementaryContentPresenterAP(SupplementaryContentPresenter ^ owner)
: Windows::UI::Xaml::Automation::Peers::FrameworkElementAutomationPeer(owner)
{
}
};
}
}

View File

@@ -1,33 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "BooleanNegationConverter.h"
using namespace CalculatorApp::Converters;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml::Interop;
Object ^ BooleanNegationConverter::Convert(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto boxedBool = dynamic_cast<Box<bool> ^>(value);
auto boolValue = (boxedBool != nullptr && boxedBool->Value);
return !boolValue;
}
Object ^ BooleanNegationConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto boxedBool = dynamic_cast<Box<bool> ^>(value);
auto boolValue = (boxedBool != nullptr && boxedBool->Value);
return !boolValue;
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to false and vice versa.
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class BooleanNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedBool = value as bool?;
var boolValue = (boxedBool != null && boxedBool.Value);
return !boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var boxedBool = (value as bool?);
var boolValue = (boxedBool != null && boxedBool.Value);
return !boolValue;
}
}
}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to false and vice versa.
/// </summary>
[Windows::Foundation::Metadata::WebHostHidden] public ref class BooleanNegationConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
}
}

View File

@@ -1,59 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "BooleanToVisibilityConverter.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Interop;
namespace CalculatorApp
{
namespace Converters
{
Object ^ BooleanToVisibilityConverter::Convert(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto boxedBool = dynamic_cast<Box<bool> ^>(value);
auto boolValue = (boxedBool != nullptr && boxedBool->Value);
return BooleanToVisibilityConverter::Convert(boolValue);
}
Object ^ BooleanToVisibilityConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto visibility = dynamic_cast<Box<Visibility> ^>(value);
return (visibility != nullptr && visibility->Value == Visibility::Visible);
}
Object ^ BooleanToVisibilityNegationConverter::Convert(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto boxedBool = dynamic_cast<Box<bool> ^>(value);
auto boolValue = (boxedBool != nullptr && boxedBool->Value);
return BooleanToVisibilityConverter::Convert(!boolValue);
}
Object ^ BooleanToVisibilityNegationConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto visibility = dynamic_cast<Box<Visibility> ^>(value);
return (visibility != nullptr && visibility->Value != Visibility::Visible);
}
}
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to <see cref="Visibility.Visible"/> and false
/// to <see cref="Visibility.Collapsed"/>.
/// </summary>
public sealed class BooleanToVisibilityConverter : Windows.UI.Xaml.Data.IValueConverter
{
public static Windows.UI.Xaml.Visibility Convert(bool visibility)
{
return visibility ? Windows.UI.Xaml.Visibility.Visible : Windows.UI.Xaml.Visibility.Collapsed;
}
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedBool = (value as bool?);
var boolValue = (boxedBool != null && boxedBool.Value);
return BooleanToVisibilityConverter.Convert(boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var visibility = (value as Visibility?);
return (visibility != null && visibility.Value == Visibility.Visible);
}
}
/// <summary>
/// Value converter that translates false to <see cref="Visibility.Visible"/> and true
/// to <see cref="Visibility.Collapsed"/>.
/// </summary>
public sealed class BooleanToVisibilityNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedBool = (value as bool?);
var boolValue = (boxedBool != null && boxedBool.Value);
return BooleanToVisibilityConverter.Convert(!boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var visibility = (value as Visibility?);
return (visibility != null && visibility.Value != Visibility.Visible);
}
}
}
}

View File

@@ -1,52 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to <see cref="Visibility::Visible"/> and false
/// to <see cref="Visibility::Collapsed"/>.
/// </summary>
public
ref class BooleanToVisibilityConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
static constexpr Windows::UI::Xaml::Visibility Convert(bool visibility)
{
return visibility ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
}
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
/// <summary>
/// Value converter that translates false to <see cref="Visibility::Visible"/> and true
/// to <see cref="Visibility::Collapsed"/>.
/// </summary>
public
ref class BooleanToVisibilityNegationConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
}
}

View File

@@ -1,38 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "ExpressionItemTemplateSelector.h"
#include "CalcViewModel/Common/DisplayExpressionToken.h"
using namespace CalculatorApp::Common;
namespace CalculatorApp
{
namespace Converters
{
Windows::UI::Xaml::DataTemplate
^ ExpressionItemTemplateSelector::SelectTemplateCore(Platform::Object ^ item, Windows::UI::Xaml::DependencyObject ^ container)
{
DisplayExpressionToken ^ token = dynamic_cast<DisplayExpressionToken ^>(item);
if (token != nullptr)
{
Common::TokenType type = token->Type;
switch (type)
{
case TokenType::Operator:
return m_operatorTemplate;
case TokenType::Operand:
return m_operandTemplate;
case TokenType::Separator:
return m_separatorTemplate;
default:
throw ref new Platform::Exception(E_FAIL, L"Invalid token type");
}
}
return m_separatorTemplate;
}
}
}

View File

@@ -0,0 +1,83 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace Converters
{
[Windows.UI.Xaml.Data.Bindable]
public sealed class ExpressionItemTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
DisplayExpressionToken token = (item as DisplayExpressionToken);
if (token != null)
{
CalculatorApp.ViewModel.Common.TokenType type = token.Type;
switch (type)
{
case TokenType.Operator:
return m_operatorTemplate;
case TokenType.Operand:
return m_operandTemplate;
case TokenType.Separator:
return m_separatorTemplate;
default:
throw new Exception("Invalid token type");
}
}
return m_separatorTemplate;
}
public Windows.UI.Xaml.DataTemplate OperatorTemplate
{
get
{
return m_operatorTemplate;
}
set
{
m_operatorTemplate = value;
}
}
public Windows.UI.Xaml.DataTemplate OperandTemplate
{
get
{
return m_operandTemplate;
}
set
{
m_operandTemplate = value;
}
}
public Windows.UI.Xaml.DataTemplate SeparatorTemplate
{
get
{
return m_separatorTemplate;
}
set
{
m_separatorTemplate = value;
}
}
private Windows.UI.Xaml.DataTemplate m_operatorTemplate;
private Windows.UI.Xaml.DataTemplate m_operandTemplate;
private Windows.UI.Xaml.DataTemplate m_separatorTemplate;
}
}
}

View File

@@ -1,57 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Converters
{
[Windows::UI::Xaml::Data::Bindable] public ref class ExpressionItemTemplateSelector sealed : public Windows::UI::Xaml::Controls::DataTemplateSelector
{
public:
virtual Windows::UI::Xaml::DataTemplate ^ SelectTemplateCore(Platform::Object ^ item, Windows::UI::Xaml::DependencyObject ^ container) override;
property Windows::UI::Xaml::DataTemplate^ OperatorTemplate
{
Windows::UI::Xaml::DataTemplate^ get()
{
return m_operatorTemplate;
}
void set(Windows::UI::Xaml::DataTemplate^ val)
{
m_operatorTemplate = val;
}
}
property Windows::UI::Xaml::DataTemplate^ OperandTemplate
{
Windows::UI::Xaml::DataTemplate^ get()
{
return m_operandTemplate;
}
void set(Windows::UI::Xaml::DataTemplate^ val)
{
m_operandTemplate = val;
}
}
property Windows::UI::Xaml::DataTemplate^ SeparatorTemplate
{
Windows::UI::Xaml::DataTemplate^ get()
{
return m_separatorTemplate;
}
void set(Windows::UI::Xaml::DataTemplate^ val)
{
m_separatorTemplate = val;
}
}
private:
Windows::UI::Xaml::DataTemplate^ m_operatorTemplate;
Windows::UI::Xaml::DataTemplate ^ m_operandTemplate;
Windows::UI::Xaml::DataTemplate ^ m_separatorTemplate;
};
}
}

View File

@@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "ItemSizeToVisibilityConverter.h"
#include "BooleanToVisibilityConverter.h"
using namespace CalculatorApp::Converters;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Interop;
Object ^ ItemSizeToVisibilityConverter::Convert(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto items = dynamic_cast<Box<int> ^>(value);
auto boolValue = (items != nullptr && (items->Value == 0));
return BooleanToVisibilityConverter::Convert(boolValue);
}
Object ^ ItemSizeToVisibilityConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
throw ref new NotImplementedException();
}
Object ^ ItemSizeToVisibilityNegationConverter::Convert(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto items = dynamic_cast<Box<int> ^>(value);
auto boolValue = (items != nullptr && (items->Value > 0));
return BooleanToVisibilityConverter::Convert(boolValue);
}
Object ^ ItemSizeToVisibilityNegationConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
throw ref new NotImplementedException();
}

View File

@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
namespace CalculatorApp
{
namespace Converters
{
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class ItemSizeToVisibilityConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var items = (value as int?);
var boolValue = (items != null && (items.Value == 0));
return BooleanToVisibilityConverter.Convert(boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
public sealed class ItemSizeToVisibilityNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var items = (value as int?);
var boolValue = (items != null && (items.Value > 0));
return BooleanToVisibilityConverter.Convert(boolValue);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
}

View File

@@ -1,37 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Converters
{
[Windows::Foundation::Metadata::WebHostHidden] public ref class ItemSizeToVisibilityConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
public
ref class ItemSizeToVisibilityNegationConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
}
}

View File

@@ -1,61 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "RadixToStringConverter.h"
#include "CalcManager/Header Files/RadixType.h"
#include "CalcViewModel/Common/AppResourceProvider.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::ApplicationModel::Resources;
namespace CalculatorApp
{
namespace Converters
{
Object ^ RadixToStringConverter::Convert(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
(void)targetType; // Unused parameter
(void)parameter; // Unused parameter
(void)language; // Unused parameter
auto boxedInt = dynamic_cast<Box<int> ^>(value);
Platform::String ^ convertedValue;
auto resourceLoader = AppResourceProvider::GetInstance();
switch (boxedInt->Value)
{
case RadixType::Binary:
{
convertedValue = resourceLoader->GetResourceString("Bin");
break;
}
case RadixType::Octal:
{
convertedValue = resourceLoader->GetResourceString("Oct");
break;
}
case RadixType::Decimal:
{
convertedValue = resourceLoader->GetResourceString("Dec");
break;
}
case RadixType::Hex:
{
convertedValue = resourceLoader->GetResourceString("Hex");
break;
}
default:
break;
};
return convertedValue;
}
Object ^ RadixToStringConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
throw ref new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
using System;
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to false and vice versa.
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class RadixToStringConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedInt = (value as int?);
string convertedValue = null;
var resourceLoader = AppResourceProvider.GetInstance();
switch (boxedInt.Value)
{
case (int)RadixType.Binary:
{
convertedValue = resourceLoader.GetResourceString("Bin");
break;
}
case (int)RadixType.Octal:
{
convertedValue = resourceLoader.GetResourceString("Oct");
break;
}
case (int)RadixType.Decimal:
{
convertedValue = resourceLoader.GetResourceString("Dec");
break;
}
case (int)RadixType.Hex:
{
convertedValue = resourceLoader.GetResourceString("Hex");
break;
}
default:
break;
}
return convertedValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Converters
{
/// <summary>
/// Value converter that translates true to false and vice versa.
/// </summary>
[Windows::Foundation::Metadata::WebHostHidden] public ref class RadixToStringConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "VisibilityNegationConverter.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Interop;
namespace CalculatorApp
{
namespace Common
{
Object ^ VisibilityNegationConverter::Convert(Object ^ value, TypeName /*targetType*/, Object ^ /*parameter*/, String ^ /*language*/)
{
auto boxedVisibility = dynamic_cast<Box<Visibility> ^>(value);
if (boxedVisibility != nullptr && boxedVisibility->Value == Visibility::Collapsed)
{
return Visibility::Visible;
}
return Visibility::Collapsed;
}
Object ^ VisibilityNegationConverter::ConvertBack(Object ^ value, TypeName targetType, Object ^ parameter, String ^ language)
{
return Convert(value, targetType, parameter, language);
}
}
}

View File

@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace Common
{
/// <summary>
/// Value converter that translates Visible to Collapsed and vice versa
/// </summary>
[Windows.Foundation.Metadata.WebHostHidden]
public sealed class VisibilityNegationConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var boxedVisibility = (value as Visibility?);
if (boxedVisibility != null && boxedVisibility.Value == Visibility.Collapsed)
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return Convert(value, targetType, parameter, language);
}
}
}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace Common
{
/// <summary>
/// Value converter that translates Visible to Collapsed and vice versa
/// </summary>
[Windows::Foundation::Metadata::WebHostHidden] public ref class VisibilityNegationConverter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object
^ Convert(Platform::Object ^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object ^ parameter, Platform::String ^ language);
virtual Platform::Object
^ ConvertBack(
Platform::Object ^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object ^ parameter,
Platform::String ^ language);
};
}
}

View File

@@ -1,4 +1,4 @@
<UserControl x:Class="CalculatorApp.EquationStylePanelControl"
<UserControl x:Class="CalculatorApp.EquationStylePanelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

View File

@@ -1,283 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "EquationStylePanelControl.xaml.h"
#include "CalcViewModel/Common/AppResourceProvider.h"
using namespace CalculatorApp;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
using namespace Windows::UI::Xaml::Shapes;
using namespace GraphControl;
DEPENDENCY_PROPERTY_INITIALIZATION(EquationStylePanelControl, SelectedColor);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationStylePanelControl, SelectedStyle);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationStylePanelControl, EnableLineStylePicker);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationStylePanelControl, SelectedColorIndex);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationStylePanelControl, AvailableColors);
EquationStylePanelControl::EquationStylePanelControl()
{
InitializeComponent();
auto allStyles = ref new Vector<EquationLineStyle>();
allStyles->Append(::EquationLineStyle::Solid);
allStyles->Append(::EquationLineStyle::Dash);
allStyles->Append(::EquationLineStyle::Dot);
StyleChooserBox->ItemsSource = allStyles;
}
void EquationStylePanelControl::SelectionChanged(Object ^ /*sender */, SelectionChangedEventArgs ^ e)
{
if (e->AddedItems->Size > 0)
{
auto brush = dynamic_cast<SolidColorBrush ^>(e->AddedItems->GetAt(0));
if (brush == nullptr)
{
SelectedColor = Colors::Black;
}
else
{
SelectedColor = brush->Color;
}
TraceLogger::GetInstance()->LogGraphLineStyleChanged(LineStyleType::Color);
}
}
void EquationStylePanelControl::OnSelectedColorPropertyChanged(Color /*oldColor*/, Color newColor)
{
SelectColor(newColor);
}
void EquationStylePanelControl::ColorChooserLoaded(Object ^ sender, RoutedEventArgs ^ e)
{
SelectColor(SelectedColor);
}
void EquationStylePanelControl::SelectColor(Color selectedColor)
{
for (unsigned int i = 0; i < ColorChooser->Items->Size; i++)
{
auto item = ColorChooser->Items->GetAt(i);
auto brush = static_cast<SolidColorBrush ^>(item);
auto gridViewItem = dynamic_cast<GridViewItem ^>(ColorChooser->ContainerFromItem(brush));
if (!gridViewItem)
{
continue;
}
if (Utils::AreColorsEqual(brush->Color, selectedColor))
{
gridViewItem->IsSelected = true;
SelectedColorIndex = i;
return;
}
else
{
gridViewItem->IsSelected = false;
}
}
}
void EquationStylePanelControl::OnSelectedStylePropertyChanged(EquationLineStyle oldStyle, EquationLineStyle newStyle)
{
if (oldStyle != newStyle)
{
SelectStyle(newStyle);
TraceLogger::GetInstance()->LogGraphLineStyleChanged(LineStyleType::Pattern);
}
}
void EquationStylePanelControl::SelectStyle(EquationLineStyle selectedStyle)
{
for (auto item : StyleChooserBox->Items->GetView())
{
auto style = static_cast<EquationLineStyle>(item);
auto comboBoxItem = dynamic_cast<ComboBoxItem ^>(StyleChooserBox->ContainerFromItem(style));
if (!comboBoxItem)
{
continue;
}
if (style == selectedStyle)
{
comboBoxItem->IsSelected = true;
return;
}
else
{
comboBoxItem->IsSelected = false;
}
}
}
void EquationStylePanelControl::StyleChooserBox_SelectionChanged(Object ^ sender, SelectionChangedEventArgs ^ e)
{
if (e->AddedItems->Size > 0)
{
SelectedStyle = static_cast<EquationLineStyle>(e->AddedItems->GetAt(0));
}
}
void EquationStylePanelControl::StyleChooserBox_Loaded(Object ^ sender, RoutedEventArgs ^ e)
{
SelectStyle(SelectedStyle);
}
String ^ EquationStylePanelControl::GetColorAutomationName(Brush ^ brush)
{
auto resourceLoader = AppResourceProvider::GetInstance();
auto color = static_cast<SolidColorBrush ^>(brush);
auto lightDictionary = static_cast<ResourceDictionary ^>(Application::Current->Resources->ThemeDictionaries->Lookup(L"Light"));
auto darkDictionary = static_cast<ResourceDictionary ^>(Application::Current->Resources->ThemeDictionaries->Lookup(L"Default"));
auto highContrast = static_cast<ResourceDictionary ^>(Application::Current->Resources->ThemeDictionaries->Lookup(L"HighContrast"));
if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush1"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush1")))
{
return resourceLoader->GetResourceString("equationColor1AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush2"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush2")))
{
return resourceLoader->GetResourceString("equationColor2AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush3"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush3")))
{
return resourceLoader->GetResourceString("equationColor3AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush4"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush4")))
{
return resourceLoader->GetResourceString("equationColor4AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush5"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush5")))
{
return resourceLoader->GetResourceString("equationColor5AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush6"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush6")))
{
return resourceLoader->GetResourceString("equationColor6AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush7"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush7")))
{
return resourceLoader->GetResourceString("equationColor7AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush8"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush8")))
{
return resourceLoader->GetResourceString("equationColor8AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush9"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush9")))
{
return resourceLoader->GetResourceString("equationColor9AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush10"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush10")))
{
return resourceLoader->GetResourceString("equationColor10AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush11"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush11")))
{
return resourceLoader->GetResourceString("equationColor11AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush12"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush12")))
{
return resourceLoader->GetResourceString("equationColor12AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush13"))
|| color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush13")))
{
return resourceLoader->GetResourceString("equationColor13AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(darkDictionary->Lookup(L"EquationBrush14")))
{
return resourceLoader->GetResourceString("equationColor14WhiteAutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(lightDictionary->Lookup(L"EquationBrush14")))
{
return resourceLoader->GetResourceString("equationColor14BlackAutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(highContrast->Lookup(L"EquationBrush1")))
{
return resourceLoader->GetResourceString("equationHighContrastColor1AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(highContrast->Lookup(L"EquationBrush2")))
{
return resourceLoader->GetResourceString("equationHighContrastColor2AutomationName");
}
else if (color == safe_cast<SolidColorBrush ^>(highContrast->Lookup(L"EquationBrush3")))
{
return resourceLoader->GetResourceString("equationHighContrastColor3AutomationName");
}
else
{
return resourceLoader->GetResourceString("equationHighContrastColor4AutomationName");
}
}
String ^ EquationStylePanelControl::GetLineAutomationName(Object ^ line)
{
auto resourceLoader = AppResourceProvider::GetInstance();
auto lineStyle = static_cast<Box<EquationLineStyle> ^>(line)->Value;
switch (lineStyle)
{
case ::EquationLineStyle::Dot:
return resourceLoader->GetResourceString("dotLineStyleAutomationName");
break;
case ::EquationLineStyle::Dash:
return resourceLoader->GetResourceString("dashLineStyleAutomationName");
break;
case ::EquationLineStyle::Solid:
default:
return resourceLoader->GetResourceString("solidLineStyleAutomationName");
break;
}
}
DoubleCollection ^ EquationStylePanelControl::GetLinePattern(Object ^ line)
{
auto lineStyle = static_cast<Box<EquationLineStyle> ^>(line)->Value;
auto linePattern = ref new DoubleCollection();
switch (lineStyle)
{
case ::EquationLineStyle::Dot:
linePattern->Append(1);
break;
case ::EquationLineStyle::Dash:
linePattern->Append(2);
linePattern->Append(1);
break;
default:
break;
}
return linePattern;
}

View File

@@ -0,0 +1,325 @@
using CalculatorApp.ViewModel.Common;
using GraphControl;
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace CalculatorApp
{
public sealed partial class EquationStylePanelControl : UserControl
{
public EquationStylePanelControl()
{
InitializeComponent();
var allStyles = new List<EquationLineStyle>();
allStyles.Add(EquationLineStyle.Solid);
allStyles.Add(EquationLineStyle.Dash);
allStyles.Add(EquationLineStyle.Dot);
StyleChooserBox.ItemsSource = allStyles;
}
public Windows.UI.Color SelectedColor
{
get { return (Windows.UI.Color)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedColorProperty =
DependencyProperty.Register(nameof(SelectedColor), typeof(Windows.UI.Color), typeof(EquationStylePanelControl), new PropertyMetadata(Windows.UI.Colors.Black, (sender, args) =>
{
var self = (EquationStylePanelControl)sender;
self.OnSelectedColorPropertyChanged((Windows.UI.Color)args.OldValue, (Windows.UI.Color)args.NewValue);
}));
public GraphControl.EquationLineStyle SelectedStyle
{
get { return (GraphControl.EquationLineStyle)GetValue(SelectedStyleProperty); }
set { SetValue(SelectedStyleProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedStyle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedStyleProperty =
DependencyProperty.Register(nameof(SelectedStyle), typeof(GraphControl.EquationLineStyle), typeof(EquationStylePanelControl), new PropertyMetadata(GraphControl.EquationLineStyle.Solid, (sender, args) =>
{
var self = (EquationStylePanelControl)sender;
self.OnSelectedStylePropertyChanged((GraphControl.EquationLineStyle)args.OldValue, (GraphControl.EquationLineStyle)args.NewValue);
}));
public int SelectedColorIndex
{
get { return (int)GetValue(SelectedColorIndexProperty); }
set { SetValue(SelectedColorIndexProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedColorIndex. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedColorIndexProperty =
DependencyProperty.Register(nameof(SelectedColorIndex), typeof(int), typeof(EquationStylePanelControl), new PropertyMetadata(default(int)));
public IList<Windows.UI.Xaml.Media.SolidColorBrush> AvailableColors
{
get { return (IList<Windows.UI.Xaml.Media.SolidColorBrush>)GetValue(AvailableColorsProperty); }
set { SetValue(AvailableColorsProperty, value); }
}
// Using a DependencyProperty as the backing store for AvailableColors. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AvailableColorsProperty =
DependencyProperty.Register(nameof(AvailableColors), typeof(IList<Windows.UI.Xaml.Media.SolidColorBrush>), typeof(EquationStylePanelControl), new PropertyMetadata(null));
public bool EnableLineStylePicker
{
get { return (bool)GetValue(EnableLineStylePickerProperty); }
set { SetValue(EnableLineStylePickerProperty, value); }
}
// Using a DependencyProperty as the backing store for EnableLineStylePicker. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EnableLineStylePickerProperty =
DependencyProperty.Register(nameof(EnableLineStylePicker), typeof(bool), typeof(EquationStylePanelControl), new PropertyMetadata(default(bool)));
public static Windows.UI.Xaml.Media.DoubleCollection GetLinePattern(object line)
{
var lineStyle = ((EquationLineStyle?)line).Value;
var linePattern = new DoubleCollection();
switch (lineStyle)
{
case EquationLineStyle.Dot:
linePattern.Add(1);
break;
case EquationLineStyle.Dash:
linePattern.Add(2);
linePattern.Add(1);
break;
default:
break;
}
return linePattern;
}
public static string GetLineAutomationName(object line)
{
var resourceLoader = AppResourceProvider.GetInstance();
var lineStyle = ((EquationLineStyle?)line).Value;
switch (lineStyle)
{
case EquationLineStyle.Dot:
return resourceLoader.GetResourceString("dotLineStyleAutomationName");
case EquationLineStyle.Dash:
return resourceLoader.GetResourceString("dashLineStyleAutomationName");
case EquationLineStyle.Solid:
default:
return resourceLoader.GetResourceString("solidLineStyleAutomationName");
}
}
public static string GetColorAutomationName(Windows.UI.Xaml.Media.Brush brush)
{
var resourceLoader = AppResourceProvider.GetInstance();
var color = ((SolidColorBrush)brush);
var lightDictionary = (ResourceDictionary)(Application.Current.Resources.ThemeDictionaries["Light"]);
var darkDictionary = (ResourceDictionary)(Application.Current.Resources.ThemeDictionaries["Default"]);
var highContrast = (ResourceDictionary)(Application.Current.Resources.ThemeDictionaries["HighContrast"]);
if (color == (SolidColorBrush)(lightDictionary["EquationBrush1"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush1"]))
{
return resourceLoader.GetResourceString("equationColor1AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush2"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush2"]))
{
return resourceLoader.GetResourceString("equationColor2AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush3"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush3"]))
{
return resourceLoader.GetResourceString("equationColor3AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush4"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush4"]))
{
return resourceLoader.GetResourceString("equationColor4AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush5"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush5"]))
{
return resourceLoader.GetResourceString("equationColor5AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush6"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush6"]))
{
return resourceLoader.GetResourceString("equationColor6AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush7"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush7"]))
{
return resourceLoader.GetResourceString("equationColor7AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush8"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush8"]))
{
return resourceLoader.GetResourceString("equationColor8AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush9"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush9"]))
{
return resourceLoader.GetResourceString("equationColor9AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush10"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush10"]))
{
return resourceLoader.GetResourceString("equationColor10AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush11"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush11"]))
{
return resourceLoader.GetResourceString("equationColor11AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush12"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush12"]))
{
return resourceLoader.GetResourceString("equationColor12AutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush13"])
|| color == (SolidColorBrush)(darkDictionary["EquationBrush13"]))
{
return resourceLoader.GetResourceString("equationColor13AutomationName");
}
else if (color == (SolidColorBrush)(darkDictionary["EquationBrush14"]))
{
return resourceLoader.GetResourceString("equationColor14WhiteAutomationName");
}
else if (color == (SolidColorBrush)(lightDictionary["EquationBrush14"]))
{
return resourceLoader.GetResourceString("equationColor14BlackAutomationName");
}
else if (color == (SolidColorBrush)(highContrast["EquationBrush1"]))
{
return resourceLoader.GetResourceString("equationHighContrastColor1AutomationName");
}
else if (color == (SolidColorBrush)(highContrast["EquationBrush2"]))
{
return resourceLoader.GetResourceString("equationHighContrastColor2AutomationName");
}
else if (color == (SolidColorBrush)(highContrast["EquationBrush3"]))
{
return resourceLoader.GetResourceString("equationHighContrastColor3AutomationName");
}
else
{
return resourceLoader.GetResourceString("equationHighContrastColor4AutomationName");
}
}
private void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
var brush = (e.AddedItems[0] as SolidColorBrush);
if (brush == null)
{
SelectedColor = Colors.Black;
}
else
{
SelectedColor = brush.Color;
}
CalculatorApp.ViewModel.Common.TraceLogger.GetInstance().LogGraphLineStyleChanged(LineStyleType.Color);
}
}
private void OnSelectedColorPropertyChanged(Color oldColor, Color newColor)
{
SelectColor(newColor);
}
private void ColorChooserLoaded(object sender, RoutedEventArgs e)
{
SelectColor(SelectedColor);
}
private void SelectColor(Color selectedColor)
{
for (int i = 0; i < ColorChooser.Items.Count; i++)
{
var item = ColorChooser.Items[i];
var brush = ((SolidColorBrush)item);
var gridViewItem = (ColorChooser.ContainerFromItem(brush) as GridViewItem);
if (gridViewItem == null)
{
continue;
}
if (Utilities.AreColorsEqual(brush.Color, selectedColor))
{
gridViewItem.IsSelected = true;
SelectedColorIndex = i;
return;
}
else
{
gridViewItem.IsSelected = false;
}
}
}
private void OnSelectedStylePropertyChanged(EquationLineStyle oldStyle, EquationLineStyle newStyle)
{
if (oldStyle != newStyle)
{
SelectStyle(newStyle);
CalculatorApp.ViewModel.Common.TraceLogger.GetInstance().LogGraphLineStyleChanged(LineStyleType.Pattern);
}
}
private void SelectStyle(EquationLineStyle selectedStyle)
{
foreach (var item in StyleChooserBox.Items)
{
var style = ((EquationLineStyle)item);
var comboBoxItem = (StyleChooserBox.ContainerFromItem(style) as ComboBoxItem);
if (comboBoxItem == null)
{
continue;
}
if (style == selectedStyle)
{
comboBoxItem.IsSelected = true;
return;
}
else
{
comboBoxItem.IsSelected = false;
}
}
}
private void StyleChooserBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
SelectedStyle = ((EquationLineStyle)e.AddedItems[0]);
}
}
private void StyleChooserBox_Loaded(object sender, RoutedEventArgs e)
{
SelectStyle(SelectedStyle);
}
}
}

View File

@@ -1,40 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "EquationStylePanelControl.g.h"
#include "CalcViewModel/Common/Utils.h"
#include "CalcViewModel/Common/TraceLogger.h"
namespace CalculatorApp
{
[Windows::Foundation::Metadata::WebHostHidden] public ref class EquationStylePanelControl sealed
{
public:
EquationStylePanelControl();
DEPENDENCY_PROPERTY_OWNER(EquationStylePanelControl);
DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(Windows::UI::Color, SelectedColor, Windows::UI::Colors::Black);
DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(GraphControl::EquationLineStyle, SelectedStyle, GraphControl::EquationLineStyle::Solid);
DEPENDENCY_PROPERTY(int, SelectedColorIndex);
DEPENDENCY_PROPERTY_WITH_DEFAULT(Windows::Foundation::Collections::IVector<Windows::UI::Xaml::Media::SolidColorBrush ^> ^, AvailableColors, nullptr);
DEPENDENCY_PROPERTY(bool, EnableLineStylePicker);
static Windows::UI::Xaml::Media::DoubleCollection ^ GetLinePattern(Platform::Object ^ line);
static Platform::String ^ GetLineAutomationName(Platform::Object ^ line);
static Platform::String ^ GetColorAutomationName(Windows::UI::Xaml::Media::Brush ^ color);
private:
void SelectionChanged(Platform::Object ^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs ^ e);
void OnSelectedColorPropertyChanged(Windows::UI::Color oldColor, Windows::UI::Color newColor);
void ColorChooserLoaded(
Platform::Object ^ sender,
Windows::UI::Xaml::RoutedEventArgs ^ e);
void SelectColor(Windows::UI::Color selectedColor);
void OnSelectedStylePropertyChanged(GraphControl::EquationLineStyle oldStyle, GraphControl::EquationLineStyle newStyle);
void SelectStyle(GraphControl::EquationLineStyle selectedStyle);
void StyleChooserBox_SelectionChanged(Platform::Object ^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs ^ e);
void StyleChooserBox_Loaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
};
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel;
using Windows.UI.Xaml;
namespace CalculatorApp
{
namespace TemplateSelectors
{
public sealed class KeyGraphFeaturesTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
public KeyGraphFeaturesTemplateSelector()
{
}
public Windows.UI.Xaml.DataTemplate RichEditTemplate { get; set; }
public Windows.UI.Xaml.DataTemplate GridTemplate { get; set; }
public Windows.UI.Xaml.DataTemplate TextBlockTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
var kgfItem = (KeyGraphFeaturesItem)item;
if (!kgfItem.IsText)
{
if (kgfItem.DisplayItems.Count != 0)
{
return RichEditTemplate;
}
else if (kgfItem.GridItems.Count != 0)
{
return GridTemplate;
}
}
return TextBlockTemplate;
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Calculator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft Calculator")]
[assembly: AssemblyCopyright("Copyright © Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View File

@@ -0,0 +1,31 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>

View File

@@ -2006,7 +2006,7 @@
<comment>A measurement unit for weight. (Please choose the most appropriate plural form to fit any number between 0 and 999,999,999,999,999)</comment>
</data>
<data name="UnitName_Degree" xml:space="preserve">
<value>도</value>
<value>도</value>
<comment>A measurement unit for Angle.</comment>
</data>
<data name="UnitName_Radian" xml:space="preserve">

View File

@@ -1706,7 +1706,7 @@
<comment>A measurement unit for energy. (Please choose the most appropriate plural form to fit any number between 0 and 999,999,999,999,999)</comment>
</data>
<data name="UnitName_Foot" xml:space="preserve">
<value>ຟຸດ</value>
<value>ຕີນ</value>
<comment>A measurement unit for length. (Please choose the most appropriate plural form to fit any number between 0 and 999,999,999,999,999)</comment>
</data>
<data name="UnitName_FeetPerSecond" xml:space="preserve">

View File

@@ -1122,7 +1122,7 @@
<comment>Unit conversion category name called Length</comment>
</data>
<data name="CategoryName_PowerText" xml:space="preserve">
<value>功率</value>
<value>电源</value>
<comment>Unit conversion category name called Power (eg. the power of an engine or a light bulb)</comment>
</data>
<data name="CategoryName_SpeedText" xml:space="preserve">

View File

@@ -1,36 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "KeyGraphFeaturesTemplateSelector.h"
#include "CalcViewModel/GraphingCalculator/EquationViewModel.h"
using namespace CalculatorApp::ViewModel;
using namespace CalculatorApp::TemplateSelectors;
using namespace Platform;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
DataTemplate ^ KeyGraphFeaturesTemplateSelector::SelectTemplateCore(Object ^ item)
{
auto kgfItem = static_cast<KeyGraphFeaturesItem ^>(item);
if (!kgfItem->IsText)
{
if (kgfItem->DisplayItems->Size != 0)
{
return RichEditTemplate;
}
else if (kgfItem->GridItems->Size != 0)
{
return GridTemplate;
}
}
return TextBlockTemplate;
}
DataTemplate ^ KeyGraphFeaturesTemplateSelector::SelectTemplateCore(Object ^ item, DependencyObject ^ container)
{
return SelectTemplateCore(item);
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace TemplateSelectors
{
public
ref class KeyGraphFeaturesTemplateSelector sealed : Windows::UI::Xaml::Controls::DataTemplateSelector
{
public:
KeyGraphFeaturesTemplateSelector()
{
}
property Windows::UI::Xaml::DataTemplate ^ RichEditTemplate;
property Windows::UI::Xaml::DataTemplate ^ GridTemplate;
property Windows::UI::Xaml::DataTemplate ^ TextBlockTemplate;
Windows::UI::Xaml::DataTemplate ^ SelectTemplateCore(Platform::Object ^ item) override;
Windows::UI::Xaml::DataTemplate ^ SelectTemplateCore(Platform::Object ^ item, Windows::UI::Xaml::DependencyObject ^ container) override;
};
}
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using CalculatorApp.ViewModel.Common;
namespace CalculatorApp.Utils
{
static class DelegateCommandUtils
{
public static DelegateCommand MakeDelegateCommand<TTarget>(TTarget target, Action<TTarget, object> handler)
where TTarget : class
{
WeakReference weakTarget = new WeakReference(target);
return new DelegateCommand(param =>
{
TTarget thatTarget = weakTarget.Target as TTarget;
if(null != thatTarget)
{
handler.Invoke(thatTarget, param);
}
});
}
}
}

View File

@@ -1,39 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "DispatcherTimerDelayer.h"
using namespace CalculatorApp;
using namespace Windows::UI::Xaml;
using namespace Windows::Foundation;
DispatcherTimerDelayer::DispatcherTimerDelayer(TimeSpan timeSpan)
{
m_timer = ref new DispatcherTimer();
m_timer->Interval = timeSpan;
auto interval = m_timer->Interval;
m_timer->Tick += ref new EventHandler<Object ^>(this, &DispatcherTimerDelayer::Timer_Tick);
}
void DispatcherTimerDelayer::Timer_Tick(Object ^ sender, Object ^ e)
{
m_timer->Stop();
Action(this, nullptr);
}
void DispatcherTimerDelayer::Start()
{
m_timer->Start();
}
void DispatcherTimerDelayer::ResetAndStart()
{
m_timer->Stop();
m_timer->Start();
}
void DispatcherTimerDelayer::Stop()
{
m_timer->Stop();
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
namespace CalculatorApp
{
public sealed class DispatcherTimerDelayer
{
public event EventHandler<object> Action;
public DispatcherTimerDelayer(TimeSpan timeSpan)
{
m_timer = new DispatcherTimer();
m_timer.Interval = timeSpan;
var interval = m_timer.Interval;
m_timer.Tick += Timer_Tick;
}
public void Start()
{
m_timer.Start();
}
public void ResetAndStart()
{
m_timer.Stop();
m_timer.Start();
}
public void Stop()
{
m_timer.Stop();
}
private void Timer_Tick(object sender, object e)
{
m_timer.Stop();
Action?.Invoke(this, null);
}
private DispatcherTimer m_timer;
}
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "pch.h"
namespace CalculatorApp
{
public ref class DispatcherTimerDelayer sealed
{
public:
DispatcherTimerDelayer(Windows::Foundation::TimeSpan timeSpan);
void Start();
void ResetAndStart();
void Stop();
event Windows::Foundation::EventHandler<Platform::Object ^> ^ Action;
private:
void Timer_Tick(Platform::Object ^ sender, Platform::Object ^ e);
Windows::UI::Xaml::DispatcherTimer ^ m_timer;
};
}

View File

@@ -1,102 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "VisualTree.h"
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Platform;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;
using namespace Calculator::Utils;
FrameworkElement ^ VisualTree::FindDescendantByName(DependencyObject ^ element, String ^ name)
{
if (element == nullptr || name == nullptr || name->Length() == 0)
{
return nullptr;
}
auto frameworkElement = dynamic_cast<FrameworkElement ^>(element);
if (frameworkElement != nullptr && name->Equals(frameworkElement->Name))
{
return frameworkElement;
}
auto childCount = VisualTreeHelper::GetChildrenCount(element);
for (int i = 0; i < childCount; i++)
{
auto result = FindDescendantByName(VisualTreeHelper::GetChild(element, i), name);
if (result != nullptr)
{
return result;
}
}
return nullptr;
}
DependencyObject ^ VisualTree::FindDescendant(DependencyObject ^ element, TypeName typeName)
{
DependencyObject ^ retValue = nullptr;
auto childrenCount = VisualTreeHelper::GetChildrenCount(element);
for (auto i = 0; i < childrenCount; i++)
{
auto child = VisualTreeHelper::GetChild(element, i);
if (child->GetType() == typeName)
{
retValue = child;
break;
}
retValue = FindDescendant(child, typeName);
if (retValue != nullptr)
{
break;
}
}
return retValue;
}
FrameworkElement ^ VisualTree::FindAscendantByName(DependencyObject ^ element, String ^ name)
{
if (element == nullptr || name == nullptr || name->Length() == 0)
{
return nullptr;
}
auto parent = VisualTreeHelper::GetParent(element);
if (parent == nullptr)
{
return nullptr;
}
auto frameworkElement = dynamic_cast<FrameworkElement ^>(parent);
if (frameworkElement != nullptr && name->Equals(frameworkElement->Name))
{
return frameworkElement;
}
return FindAscendantByName(parent, name);
}
Object ^ VisualTree::FindAscendant(DependencyObject ^ element, TypeName typeName)
{
auto parent = VisualTreeHelper::GetParent(element);
if (parent == nullptr)
{
return nullptr;
}
if (parent->GetType() == typeName)
{
return parent;
}
return FindAscendant(parent, typeName);
}

View File

@@ -0,0 +1,134 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
// Light C++/CX port of Microsoft.Toolkit.Uwp.UI.Extensions.VisualTree from the Windows Community toolkit
// Original version here:
// https://raw.githubusercontent.com/windows-toolkit/WindowsCommunityToolkit/master/Microsoft.Toolkit.Uwp.UI/Extensions/Tree/VisualTree.cs
namespace Calculator.Utils
{
/// <summary>
/// Defines a collection of extensions methods for UI.
/// </summary>
sealed class VisualTree
{
/// <summary>
/// Find descendant <see cref="Windows.UI.Xaml.FrameworkElement ^"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
internal static FrameworkElement FindDescendantByName(DependencyObject element, string name)
{
if (element == null || name == null || name.Length == 0)
{
return null;
}
var frameworkElement = (element as FrameworkElement);
if (frameworkElement != null && name.Equals(frameworkElement.Name))
{
return frameworkElement;
}
var childCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childCount; i++)
{
var result = FindDescendantByName(VisualTreeHelper.GetChild(element, i), name);
if (result != null)
{
return result;
}
}
return null;
}
/// <summary>
/// Find first descendant control of a specified type.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="type">Type of descendant.</param>
/// <returns>Descendant control or null if not found.</returns>
private static DependencyObject FindDescendant(DependencyObject element, Type typeName)
{
DependencyObject retValue = null;
var childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
if (child.GetType() == typeName)
{
retValue = child;
break;
}
retValue = FindDescendant(child, typeName);
if (retValue != null)
{
break;
}
}
return retValue;
}
/// <summary>
/// Find visual ascendant <see cref="Windows.UI.Xaml.FrameworkElement ^"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
private static FrameworkElement FindAscendantByName(DependencyObject element, string name)
{
if (element == null || name == null || name.Length == 0)
{
return null;
}
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return null;
}
var frameworkElement = (parent as FrameworkElement);
if (frameworkElement != null && name.Equals(frameworkElement.Name))
{
return frameworkElement;
}
return FindAscendantByName(parent, name);
}
/// <summary>
/// Find first visual ascendant control of a specified type.
/// </summary>
/// <param name="element">Child element.</param>
/// <param name="type">Type of ascendant to look for.</param>
/// <returns>Ascendant control or null if not found.</returns>
private static object FindAscendant(DependencyObject element, Type typeName)
{
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return null;
}
if (parent.GetType() == typeName)
{
return parent;
}
return FindAscendant(parent, typeName);
}
}
}

View File

@@ -1,50 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Light C++/CX port of Microsoft.Toolkit.Uwp.UI.Extensions.VisualTree from the Windows Community toolkit
// Original version here:
// https://raw.githubusercontent.com/windows-toolkit/WindowsCommunityToolkit/master/Microsoft.Toolkit.Uwp.UI/Extensions/Tree/VisualTree.cs
namespace Calculator::Utils
{
/// <summary>
/// Defines a collection of extensions methods for UI.
/// </summary>
ref class VisualTree sealed
{
/// <summary>
/// Find descendant <see cref="Windows::UI::Xaml::FrameworkElement ^"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
internal : static Windows::UI::Xaml::FrameworkElement ^ FindDescendantByName(Windows::UI::Xaml::DependencyObject ^ element, Platform::String ^ name);
/// <summary>
/// Find first descendant control of a specified type.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="type">Type of descendant.</param>
/// <returns>Descendant control or null if not found.</returns>
static Windows::UI::Xaml::DependencyObject
^ FindDescendant(Windows::UI::Xaml::DependencyObject ^ element, Windows::UI::Xaml::Interop::TypeName typeName);
/// <summary>
/// Find visual ascendant <see cref="Windows::UI::Xaml::FrameworkElement ^"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
static Windows::UI::Xaml::FrameworkElement ^ FindAscendantByName(Windows::UI::Xaml::DependencyObject ^ element, Platform::String ^ name);
/// <summary>
/// Find first visual ascendant control of a specified type.
/// </summary>
/// <param name="element">Child element.</param>
/// <param name="type">Type of ascendant to look for.</param>
/// <returns>Ascendant control or null if not found.</returns>
static Platform::Object ^ FindAscendant(Windows::UI::Xaml::DependencyObject ^ element, Windows::UI::Xaml::Interop::TypeName type);
};
}

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