mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-22 14:13:30 -07:00
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'
This commit is contained in:
parent
1a6ff5e2e7
commit
419a69c101
48 changed files with 9430 additions and 0 deletions
|
@ -25,6 +25,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GraphControl", "GraphContro
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TraceLogging", "TraceLogging\TraceLogging.vcxproj", "{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator", "Calculator\Calculator.csproj", "{3B773403-B0D6-4F9A-948E-512A7A5FB315}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM = Debug|ARM
|
||||
|
@ -165,6 +167,30 @@ Global
|
|||
{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x64.Build.0 = Release|x64
|
||||
{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x86.ActiveCfg = Release|Win32
|
||||
{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x86.Build.0 = Release|Win32
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x64.Build.0 = Debug|x64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x86.Build.0 = Debug|x86
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM.Build.0 = Release|ARM
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x64.ActiveCfg = Release|x64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x64.Build.0 = Release|x64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x64.Deploy.0 = Release|x64
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x86.ActiveCfg = Release|x86
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x86.Build.0 = Release|x86
|
||||
{3B773403-B0D6-4F9A-948E-512A7A5FB315}.Release|x86.Deploy.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
1778
src/Calculator/App.xaml
Normal file
1778
src/Calculator/App.xaml
Normal file
File diff suppressed because it is too large
Load diff
511
src/Calculator/App.xaml.cs
Normal file
511
src/Calculator/App.xaml.cs
Normal file
|
@ -0,0 +1,511 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
//
|
||||
// App.xaml.h
|
||||
// Declaration of the App class.
|
||||
//
|
||||
|
||||
using CalculatorApp.Common;
|
||||
using CalculatorApp.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;
|
||||
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
#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;
|
||||
}
|
||||
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.Add("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;
|
||||
};
|
||||
|
||||
// CSHARP_MIGRATION: TODO: check what is the pragma used for???
|
||||
//#pragma optimize("", off) // Turn off optimizations to work around coroutine optimization bug
|
||||
private async Task SetupJumpList()
|
||||
{
|
||||
try
|
||||
{
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
var calculatorOptions = NavCategoryGroup.CreateCalculatorCategory();
|
||||
|
||||
var jumpList = await JumpList.LoadCurrentAsync();
|
||||
jumpList.SystemGroupKind = JumpListSystemGroupKind.None;
|
||||
jumpList.Items.Clear();
|
||||
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
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(m_secondaryWindows.size());
|
||||
}
|
||||
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;
|
||||
|
||||
// CSHARP_MIGRATION: TODO: check whether or not this field is in use.
|
||||
private Windows.UI.Xaml.Controls.Primitives.Popup m_aboutPopup;
|
||||
}
|
||||
}
|
||||
|
728
src/Calculator/Calculator.csproj
Normal file
728
src/Calculator/Calculator.csproj
Normal file
|
@ -0,0 +1,728 @@
|
|||
<?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>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
|
||||
<PackageCertificateThumbprint>B06D4942DD6AAC6D5659E3AF866A11D0081C12C1</PackageCertificateThumbprint>
|
||||
<PackageCertificateKeyFile>WindowsDev_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</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>bin\x86\Release\</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>bin\ARM\Debug\</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>bin\ARM\Release\</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>bin\ARM64\Debug\</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>bin\ARM64\Release\</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>bin\x64\Debug\</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>bin\x64\Release\</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>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AppVersion Condition="'$(AppVersion)' == ''">0.0.0.0</AppVersion>
|
||||
</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>
|
||||
<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="DelegateCommand.cs" />
|
||||
<Compile Include="EquationStylePanelControl.xaml.cs">
|
||||
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="KeyGraphFeaturesTemplateSelector.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="WindowFrameService.cs" />
|
||||
<Compile Include="WinMeta.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</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.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\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>
|
||||
</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)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.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>
|
256
src/Calculator/Common/AlwaysSelectedCollectionView.cs
Normal file
256
src/Calculator/Common/AlwaysSelectedCollectionView.cs
Normal file
|
@ -0,0 +1,256 @@
|
|||
// 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(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(this, null);
|
||||
})).AsTask().Wait();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool MoveCurrentToPosition(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_source.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_currentPosition = index;
|
||||
CurrentChanged(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(this, args);
|
||||
}
|
||||
|
||||
public event EventHandler<object> CurrentChanged;
|
||||
public event CurrentChangingEventHandler CurrentChanging; // CSHARP_MIGRATION: TODO: check why this member is never being used.
|
||||
public event VectorChangedEventHandler<object> VectorChanged;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
151
src/Calculator/Common/AppLifecycleLogger.cs
Normal file
151
src/Calculator/Common/AppLifecycleLogger.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
|
||||
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 | WinMeta.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);
|
||||
}
|
||||
}
|
||||
|
834
src/Calculator/Common/KeyboardShortcuManager.cs
Normal file
834
src/Calculator/Common/KeyboardShortcuManager.cs
Normal file
|
@ -0,0 +1,834 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using CalculatorApp.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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(500); // half second
|
||||
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; // CSHARP_MIGRATION: TODO: double check if button[0] exists
|
||||
var appViewModel = (navView.DataContext as ApplicationViewModel);
|
||||
appViewModel.Mode = ViewMode.Date;
|
||||
var categoryName = AppResourceProvider.GetInstance().GetResourceString("DateCalculationModeText");
|
||||
appViewModel.CategoryName = categoryName;
|
||||
|
||||
var menuItems = ((IObservableVector<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) // CSHARP_MIGRATION: TODO: double check if this is equivalent to `if (buttons.first == buttons.second)`
|
||||
{
|
||||
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 = item as MUXC.NavigationView; // CSHARP_MIGRATION: TODO: check if this line is still needed
|
||||
|
||||
var menuItems = ((IObservableVector<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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CSHARP_MIGRATION: TODO: reinterpreted SortedDictionary<MyVirtualKey, List<WeakReference>> to SortedDictionary<char, List<WeakReference>>
|
||||
// double check this is equivalent before and after migration
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CSHARP_MIGRATION: TODO: double check below design
|
||||
// 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>();
|
||||
}
|
||||
}
|
||||
|
||||
// CSHARP_MIGRATION: TODO: double check below design
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
src/Calculator/Common/ValidatingConverters.cs
Normal file
65
src/Calculator/Common/ValidatingConverters.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
src/Calculator/Common/ViewState.cs
Normal file
17
src/Calculator/Common/ViewState.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
626
src/Calculator/Controls/EquationTextBox.cs
Normal file
626
src/Calculator/Controls/EquationTextBox.cs
Normal file
|
@ -0,0 +1,626 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using CalculatorApp.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(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(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(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(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(this, args);
|
||||
}
|
||||
|
||||
private void OnEquationFormatRequested(object sender, MathRichEditBoxFormatRequest args)
|
||||
{
|
||||
EquationFormatRequested(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
92
src/Calculator/Controls/FlipButtons.cs
Normal file
92
src/Calculator/Controls/FlipButtons.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
src/Calculator/Controls/HorizontalNoOverflowStackPanel.cs
Normal file
83
src/Calculator/Controls/HorizontalNoOverflowStackPanel.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
243
src/Calculator/Controls/MathRichEditBox.cs
Normal file
243
src/Calculator/Controls/MathRichEditBox.cs
Normal file
|
@ -0,0 +1,243 @@
|
|||
// 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 Microsoft.WRL;
|
||||
|
||||
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()
|
||||
{
|
||||
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 (GetMathTextProperty() == null)
|
||||
{
|
||||
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(this, formatRequest);
|
||||
|
||||
if (!string.IsNullOrEmpty(formatRequest.FormattedText))
|
||||
{
|
||||
newVal = formatRequest.FormattedText;
|
||||
}
|
||||
|
||||
SetValue(MathTextProperty, newVal);
|
||||
EquationSubmitted(this, new MathRichEditBoxSubmission(true, source));
|
||||
}
|
||||
else
|
||||
{
|
||||
EquationSubmitted(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
src/Calculator/Controls/RadixButton.cs
Normal file
22
src/Calculator/Controls/RadixButton.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using CalculatorApp.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
src/Calculator/Converters/BooleanNegationConverter.cs
Normal file
32
src/Calculator/Converters/BooleanNegationConverter.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
57
src/Calculator/Converters/BooleanToVisibilityConverter.cs
Normal file
57
src/Calculator/Converters/BooleanToVisibilityConverter.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
83
src/Calculator/Converters/ExpressionItemTemplateSelector.cs
Normal file
83
src/Calculator/Converters/ExpressionItemTemplateSelector.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using CalculatorApp.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)
|
||||
{
|
||||
DisplayExpressionToken token = (item as DisplayExpressionToken);
|
||||
if (token != null)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
src/Calculator/Converters/ItemSizeToVisibilityConverter.cs
Normal file
42
src/Calculator/Converters/ItemSizeToVisibilityConverter.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
58
src/Calculator/Converters/RadixToStringConverter.cs
Normal file
58
src/Calculator/Converters/RadixToStringConverter.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using CalculatorApp.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
src/Calculator/Converters/VisibilityNegationConverter.cs
Normal file
33
src/Calculator/Converters/VisibilityNegationConverter.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
src/Calculator/DelegateCommand.cs
Normal file
35
src/Calculator/DelegateCommand.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
|
||||
namespace CalculatorApp.Common
|
||||
{
|
||||
internal class DelegateCommand<TTarget> : System.Windows.Input.ICommand
|
||||
{
|
||||
public delegate void CommandHandlerFunc(object obj);
|
||||
|
||||
public DelegateCommand(TTarget target, CommandHandlerFunc func)
|
||||
{
|
||||
m_weakTarget = new WeakReference(target);
|
||||
m_function = func;
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
object target = m_weakTarget.Target;
|
||||
if (target != null && target is TTarget)
|
||||
{
|
||||
m_function(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
private CommandHandlerFunc m_function;
|
||||
private WeakReference m_weakTarget;
|
||||
}
|
||||
}
|
||||
|
133
src/Calculator/EquationStylePanelControl.xaml
Normal file
133
src/Calculator/EquationStylePanelControl.xaml
Normal file
|
@ -0,0 +1,133 @@
|
|||
<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"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="LineOptionsHeading"
|
||||
Margin="8,0,0,16"
|
||||
FontSize="20"
|
||||
FontWeight="Medium"
|
||||
AutomationProperties.HeadingLevel="Level2"/>
|
||||
<GridView x:Name="ColorChooser"
|
||||
ItemsSource="{x:Bind AvailableColors}"
|
||||
Loaded="ColorChooserLoaded"
|
||||
SelectionChanged="SelectionChanged"
|
||||
SingleSelectionFollowsFocus="False">
|
||||
<GridView.Resources>
|
||||
<Style TargetType="GridViewItem">
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="MinHeight" Value="52"/>
|
||||
<Setter Property="MinWidth" Value="52"/>
|
||||
<Setter Property="Height" Value="52"/>
|
||||
<Setter Property="Width" Value="52"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GridViewItem">
|
||||
<Grid>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal"/>
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ItemContent.Margin" Value="-2,-2,-2,-2"/>
|
||||
<Setter Target="ItemBorder.Margin" Value="2,2,2,2"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ItemContent.Margin" Value="-2,-2,-2,-2"/>
|
||||
<Setter Target="ItemBorder.Stroke" Value="{ThemeResource InkToolbarFlyoutItemBorderPressedThemeBrush}"/>
|
||||
<Setter Target="ItemBorder.Margin" Value="2,2,2,2"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Selected">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ItemContent.Margin" Value="2,2,2,2"/>
|
||||
<Setter Target="ItemBorder.Stroke" Value="{ThemeResource InkToolbarFlyoutItemBorderSelectedThemeBrush}"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="FocusStates">
|
||||
<VisualState x:Name="Focused"/>
|
||||
<VisualState x:Name="Unfocused"/>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Ellipse x:Name="ItemBorder"
|
||||
Margin="6,6,6,6"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Fill="Transparent"
|
||||
Stroke="Transparent"
|
||||
StrokeThickness="2"
|
||||
UseLayoutRounding="false"/>
|
||||
<ContentPresenter x:Name="ItemContent" UseLayoutRounding="false"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</GridView.Resources>
|
||||
<GridView.Header>
|
||||
<TextBlock x:Uid="LineColorText" Margin="8,0,8,8"/>
|
||||
</GridView.Header>
|
||||
<GridView.ItemTemplate>
|
||||
<DataTemplate x:DataType="Brush">
|
||||
<Ellipse Margin="8,8,8,8"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Fill="{x:Bind}"
|
||||
StrokeThickness="0"
|
||||
AutomationProperties.Name="{x:Bind local:EquationStylePanelControl.GetColorAutomationName((Brush))}"
|
||||
ToolTipService.ToolTip="{x:Bind local:EquationStylePanelControl.GetColorAutomationName((Brush))}"
|
||||
UseLayoutRounding="false"/>
|
||||
</DataTemplate>
|
||||
</GridView.ItemTemplate>
|
||||
<GridView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsWrapGrid MaximumRowsOrColumns="7" Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</GridView.ItemsPanel>
|
||||
</GridView>
|
||||
|
||||
<ComboBox x:Name="StyleChooserBox"
|
||||
MinWidth="200"
|
||||
Margin="8,0"
|
||||
Foreground="{ThemeResource AppControlPageTextBaseHighColorBrush}"
|
||||
Loaded="StyleChooserBox_Loaded"
|
||||
SelectedItem="{x:Bind SelectedStyle}"
|
||||
SelectionChanged="StyleChooserBox_SelectionChanged"
|
||||
Visibility="Visible"
|
||||
IsEnabled="{x:Bind EnableLineStylePicker, Mode=OneWay}">
|
||||
<ComboBox.Header>
|
||||
<TextBlock x:Uid="StyleChooserBoxHeading" Margin="0,0,8,8"/>
|
||||
</ComboBox.Header>
|
||||
<ComboBox.ItemTemplate>
|
||||
<!-- Set x:DataType to be Platform::Object so that we can pass it to the x:Bind function directly since we cannot pass an enum in c++/cx -->
|
||||
<DataTemplate x:DataType="x:Object">
|
||||
<Grid x:Name="LineGrid"
|
||||
Height="20"
|
||||
MaxWidth="200"
|
||||
AutomationProperties.Name="{x:Bind local:EquationStylePanelControl.GetLineAutomationName((x:Object))}">
|
||||
|
||||
<Line x:Name="LineItem"
|
||||
VerticalAlignment="Center"
|
||||
Stroke="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
StrokeThickness="2.5"
|
||||
StrokeDashArray="{x:Bind local:EquationStylePanelControl.GetLinePattern((x:Object))}"
|
||||
X1="0"
|
||||
X2="200"
|
||||
Y1="4"
|
||||
Y2="4"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</UserControl>
|
320
src/Calculator/EquationStylePanelControl.xaml.cs
Normal file
320
src/Calculator/EquationStylePanelControl.xaml.cs
Normal file
|
@ -0,0 +1,320 @@
|
|||
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();
|
||||
}
|
||||
|
||||
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.Append(1);
|
||||
break;
|
||||
case EquationLineStyle.Dash:
|
||||
linePattern.Append(2);
|
||||
linePattern.Append(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");
|
||||
break;
|
||||
case EquationLineStyle.Dash:
|
||||
return resourceLoader.GetResourceString("dashLineStyleAutomationName");
|
||||
break;
|
||||
case EquationLineStyle.Solid:
|
||||
default:
|
||||
return resourceLoader.GetResourceString("solidLineStyleAutomationName");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
29
src/Calculator/Properties/AssemblyInfo.cs
Normal file
29
src/Calculator/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
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("CalculatorUI")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("CalculatorUI")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
31
src/Calculator/Properties/Default.rd.xml
Normal file
31
src/Calculator/Properties/Default.rd.xml
Normal 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>
|
45
src/Calculator/Utils/DispatcherTimerDelayer.cs
Normal file
45
src/Calculator/Utils/DispatcherTimerDelayer.cs
Normal 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(this, null);
|
||||
}
|
||||
|
||||
private DispatcherTimer m_timer;
|
||||
}
|
||||
}
|
134
src/Calculator/Utils/VisualTree.cs
Normal file
134
src/Calculator/Utils/VisualTree.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
173
src/Calculator/Views/HistoryList.xaml
Normal file
173
src/Calculator/Views/HistoryList.xaml
Normal file
|
@ -0,0 +1,173 @@
|
|||
<UserControl x:Class="CalculatorApp.HistoryList"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:automation="using:CalculatorApp.Common.Automation"
|
||||
xmlns:converters="using:CalculatorApp.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:CalculatorApp.ViewModel"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
AutomationProperties.AutomationId="HistoryList"
|
||||
FlowDirection="LeftToRight"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<Style x:Key="BodyTextBlockMediumStyle"
|
||||
BasedOn="{StaticResource BodyTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Style x:Key="BodyTextBlockMediumStyle"
|
||||
BasedOn="{StaticResource BodyTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<Style x:Key="BodyTextBlockMediumStyle"
|
||||
BasedOn="{StaticResource BodyTextBlockStyle}"
|
||||
TargetType="TextBlock"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
<converters:ItemSizeToVisibilityNegationConverter x:Key="ItemSizeToVisibilityNegationConverter"/>
|
||||
<converters:ItemSizeToVisibilityConverter x:Key="ItemSizeToVisibilityConverter"/>
|
||||
<automation:NarratorNotifier x:Name="NarratorNotifier" Announcement="{x:Bind Model.HistoryAnnouncement, Mode=OneWay}"/>
|
||||
|
||||
<muxc:SymbolIconSource x:Key="DeleteSymbol" Symbol="Delete"/>
|
||||
|
||||
<muxc:SwipeItems x:Key="HistorySwipeItems" Mode="Execute">
|
||||
<muxc:SwipeItem x:Uid="DeleteHistorySwipeItem"
|
||||
IconSource="{StaticResource DeleteSymbol}"
|
||||
Invoked="OnDeleteSwipeInvoked"/>
|
||||
</muxc:SwipeItems>
|
||||
|
||||
<MenuFlyout x:Name="HistoryContextMenu">
|
||||
<MenuFlyoutItem x:Uid="CopyHistoryMenuItem"
|
||||
Click="OnCopyMenuItemClicked"
|
||||
Icon="Copy"/>
|
||||
<MenuFlyoutItem x:Uid="DeleteHistoryMenuItem"
|
||||
Click="OnDeleteMenuItemClicked"
|
||||
Icon="Delete"/>
|
||||
</MenuFlyout>
|
||||
|
||||
<DataTemplate x:Key="HistoryItemTemplate" x:DataType="model:HistoryItemViewModel">
|
||||
<muxc:SwipeControl RightItems="{StaticResource HistorySwipeItems}">
|
||||
<StackPanel Margin="0,6,4,6" Background="Transparent">
|
||||
<TextBlock x:Name="ExprTextBlock"
|
||||
Margin="0,0,0,4"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{ThemeResource BodyTextBlockMediumStyle}"
|
||||
AutomationProperties.AutomationId="HistoryItemExpression"
|
||||
AutomationProperties.Name="{x:Bind AccExpression}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind Expression}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBlock x:Name="ResultTextBlock"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{ThemeResource TitleTextBlockStyle}"
|
||||
FontWeight="SemiBold"
|
||||
AutomationProperties.AutomationId="HistoryItemValue"
|
||||
AutomationProperties.Name="{x:Bind AccResult}"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind Result}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</muxc:SwipeControl>
|
||||
</DataTemplate>
|
||||
<Style x:Key="HistoryItemContainerStyle"
|
||||
BasedOn="{StaticResource HistoryMemoryItemContainerStyle}"
|
||||
TargetType="ListViewItem">
|
||||
<Setter Property="Margin" Value="0,0,0,20"/>
|
||||
<Setter Property="ContextFlyout" Value="{StaticResource HistoryContextMenu}"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="LayoutGrid">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="{Binding RowHeight, ElementName=HistoryList, Mode=OneWay}"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup>
|
||||
<VisualState x:Name="DockedLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="560"/>
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="HistoryListRootGrid.(Grid.Row)" Value="0"/>
|
||||
<Setter Target="HistoryListRootGrid.(Grid.RowSpan)" Value="2"/>
|
||||
<Setter Target="HistoryListView.Padding" Value="0"/>
|
||||
<Setter Target="BackgroundShade.Visibility" Value="Collapsed"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DefaultLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Border x:Name="BackgroundShade"
|
||||
Grid.Row="1"
|
||||
Margin="0,-1,0,0"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
|
||||
BorderThickness="{ThemeResource HighContrastThicknessTop}"/>
|
||||
|
||||
<Grid x:Name="HistoryListRootGrid" Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock x:Name="HistoryEmpty"
|
||||
x:Uid="HistoryEmpty"
|
||||
Margin="16,14,24,0"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
FontWeight="SemiLight"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind Model.ItemsCount, Converter={StaticResource ItemSizeToVisibilityConverter}, Mode=OneWay}"/>
|
||||
<ListView x:Name="HistoryListView"
|
||||
MinHeight="60"
|
||||
Padding="0,12,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.AutomationId="HistoryListView"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="ListView_ItemClick"
|
||||
ItemContainerStyle="{StaticResource HistoryItemContainerStyle}"
|
||||
ItemTemplate="{StaticResource HistoryItemTemplate}"
|
||||
ItemsSource="{x:Bind Model.Items, Mode=OneWay}"
|
||||
SelectionMode="None"
|
||||
TabIndex="0"
|
||||
Visibility="{x:Bind Model.ItemsCount, Mode=OneWay, Converter={StaticResource ItemSizeToVisibilityNegationConverter}}">
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition/>
|
||||
<ContentThemeTransition/>
|
||||
<ReorderThemeTransition/>
|
||||
</TransitionCollection>
|
||||
</ListView.ItemContainerTransitions>
|
||||
</ListView>
|
||||
<Button x:Name="ClearHistory"
|
||||
x:Uid="ClearHistory"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource ClearAllHistoryMemoryButtonStyle}"
|
||||
AutomationProperties.AutomationId="ClearHistory"
|
||||
Command="{x:Bind Model.ClearCommand, Mode=OneWay}"
|
||||
Content=""
|
||||
Visibility="{x:Bind Model.ItemsCount, Mode=OneWay, Converter={StaticResource ItemSizeToVisibilityNegationConverter}}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
88
src/Calculator/Views/HistoryList.xaml.cs
Normal file
88
src/Calculator/Views/HistoryList.xaml.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using CalculatorApp.Common;
|
||||
using CalculatorApp.ViewModel;
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using MUXC = Microsoft.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
[Windows.Foundation.Metadata.WebHostHidden]
|
||||
public sealed partial class HistoryList : UserControl
|
||||
{
|
||||
public HistoryList()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
HistoryEmpty.FlowDirection = LocalizationService.GetInstance().GetFlowDirection();
|
||||
}
|
||||
|
||||
public CalculatorApp.ViewModel.HistoryViewModel Model
|
||||
{
|
||||
get => (CalculatorApp.ViewModel.HistoryViewModel)DataContext;
|
||||
}
|
||||
|
||||
public void ScrollToBottom()
|
||||
{
|
||||
var historyItems = HistoryListView.Items;
|
||||
if (historyItems.Count > 0)
|
||||
{
|
||||
HistoryListView.ScrollIntoView(historyItems[historyItems.Count - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
public Windows.UI.Xaml.GridLength RowHeight
|
||||
{
|
||||
get { return (Windows.UI.Xaml.GridLength)GetValue(RowHeightProperty); }
|
||||
set { SetValue(RowHeightProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for RowHeight. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty RowHeightProperty =
|
||||
DependencyProperty.Register(nameof(RowHeight), typeof(Windows.UI.Xaml.GridLength), typeof(HistoryList), new PropertyMetadata(default(Windows.UI.Xaml.GridLength)));
|
||||
|
||||
private Windows.Foundation.Rect m_visibleBounds;
|
||||
private Windows.Foundation.Rect m_coreBounds;
|
||||
|
||||
private void ListView_ItemClick(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
HistoryViewModel historyVM = (DataContext as HistoryViewModel);
|
||||
HistoryItemViewModel clickedItem = (e.ClickedItem as HistoryItemViewModel);
|
||||
|
||||
// When the user clears the history list in the overlay view and presses enter, the clickedItem is nullptr
|
||||
if (clickedItem != null && historyVM != null)
|
||||
{
|
||||
historyVM.ShowItem(clickedItem);
|
||||
}
|
||||
}
|
||||
private void OnCopyMenuItemClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var listViewItem = HistoryContextMenu.Target;
|
||||
var itemViewModel = (HistoryListView.ItemFromContainer(listViewItem) as HistoryItemViewModel);
|
||||
if (itemViewModel != null)
|
||||
{
|
||||
CopyPasteManager.CopyToClipboard(itemViewModel.Result);
|
||||
}
|
||||
}
|
||||
private void OnDeleteMenuItemClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var listViewItem = HistoryContextMenu.Target;
|
||||
var itemViewModel = (HistoryListView.ItemFromContainer(listViewItem) as HistoryItemViewModel);
|
||||
if (itemViewModel != null)
|
||||
{
|
||||
Model.DeleteItem(itemViewModel);
|
||||
}
|
||||
}
|
||||
private void OnDeleteSwipeInvoked(MUXC.SwipeItem sender, MUXC.SwipeItemInvokedEventArgs e)
|
||||
{
|
||||
var swipedItem = (e.SwipeControl.DataContext as HistoryItemViewModel);
|
||||
if (swipedItem != null)
|
||||
{
|
||||
Model.DeleteItem(swipedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
198
src/Calculator/Views/MainPage.xaml
Normal file
198
src/Calculator/Views/MainPage.xaml
Normal file
|
@ -0,0 +1,198 @@
|
|||
<Page x:Class="CalculatorApp.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:automation="using:CalculatorApp.Common.Automation"
|
||||
xmlns:common="using:CalculatorApp.Common"
|
||||
xmlns:controls="using:CalculatorApp.Controls"
|
||||
xmlns:converters="using:CalculatorApp.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:vm="using:CalculatorApp.ViewModel"
|
||||
x:Name="PageRoot"
|
||||
Background="{ThemeResource AppChromeAcrylicHostBackdropMediumLowBrush}"
|
||||
Loaded="OnPageLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<automation:NarratorNotifier x:Name="NarratorNotifier"/>
|
||||
<Style x:Name="CalculatorBaseStyle" TargetType="local:Calculator">
|
||||
<Setter Property="Margin" Value="0,0,0,0"/>
|
||||
</Style>
|
||||
<!--<Style x:Name="UnitConverterBaseStyle" TargetType="local:UnitConverter">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
<Setter Property="Margin" Value="0,0,0,0"/>
|
||||
</Style>-->
|
||||
<Style x:Key="AboutFlyoutPresenterStyle" TargetType="FlyoutPresenter">
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw"/>
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
|
||||
</Style>
|
||||
<Style x:Key="NavViewItemStyle" TargetType="muxc:NavigationViewItem">
|
||||
<Setter Property="KeyTipPlacementMode" Value="Right"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CategoryNameTextBlockStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="OpticalMarginAlignment" Value="TrimSideBearings"/>
|
||||
</Style>
|
||||
|
||||
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/>
|
||||
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="Mode">
|
||||
<VisualState x:Name="ConverterWide">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="640"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DockVisible">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="560"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MinSizeLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="{StaticResource AppMinWindowWidth}"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DefaultLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<StackPanel Visibility="Collapsed">
|
||||
<!--
|
||||
These buttons are only here to serve as the target for copy/paste commands
|
||||
they are not to be shown, only to have the command and shortcut assigned to them.
|
||||
-->
|
||||
<Button x:Name="CopyButton"
|
||||
x:Uid="copyButton"
|
||||
Command="{x:Bind Model.CopyCommand}"/>
|
||||
<Button x:Name="PasteButton"
|
||||
x:Uid="pasteButton"
|
||||
Command="{x:Bind Model.PasteCommand}"/>
|
||||
<Button x:Name="CopyButtonAlternate"
|
||||
x:Uid="copyButtonAlternate"
|
||||
Command="{x:Bind Model.CopyCommand}"/>
|
||||
<Button x:Name="PasteButtonAlternate"
|
||||
x:Uid="pasteButtonAlternate"
|
||||
Command="{x:Bind Model.PasteCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<local:TitleBar Grid.Row="0"
|
||||
AlwaysOnTopClick="TitleBarAlwaysOnTopButtonClick"
|
||||
IsAlwaysOnTopMode="{x:Bind Model.IsAlwaysOnTop, Mode=OneWay}"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Border x:Name="CalcHolder">
|
||||
<!-- PLACEHOLDER!!!! This is where the calculator goes when it is delay loaded -->
|
||||
</Border>
|
||||
<Border x:Name="DateCalcHolder">
|
||||
<!-- PLACEHOLDER!!!! This is where the date calculator goes when it is delay loaded -->
|
||||
</Border>
|
||||
<Border x:Name="GraphingCalcHolder">
|
||||
<!-- PLACEHOLDER!!!! This is where the graphing calculator goes when it is delay loaded -->
|
||||
</Border>
|
||||
<Border x:Name="ConverterHolder">
|
||||
<!-- PLACEHOLDER!!!! This is where the converter goes when it is delay loaded -->
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1"
|
||||
Height="{StaticResource HamburgerHeight}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource HamburgerHeightGridLength}"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock x:Name="Header"
|
||||
Grid.Column="1"
|
||||
Margin="8,-3,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CategoryNameTextBlockStyle}"
|
||||
Text="{x:Bind Model.CategoryName, Mode=OneWay}"
|
||||
Visibility="{x:Bind Model.IsAlwaysOnTop, Converter={StaticResource BooleanToVisibilityNegationConverter}, Mode=OneWay}"/>
|
||||
|
||||
<Button x:Name="NormalAlwaysOnTopButton"
|
||||
x:Uid="EnterAlwaysOnTopButton"
|
||||
Grid.Column="2"
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
Style="{StaticResource SquareIconButtonStyle}"
|
||||
Background="Transparent"
|
||||
FontFamily="{StaticResource CalculatorFontFamily}"
|
||||
AutomationProperties.AutomationId="NormalAlwaysOnTopButton"
|
||||
Click="AlwaysOnTopButtonClick"
|
||||
Content=""
|
||||
TabIndex="3"
|
||||
Visibility="{x:Bind Model.DisplayNormalAlwaysOnTopOption, Mode=OneWay}">
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Up" Modifiers="Menu"/>
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<muxc:NavigationView x:Name="NavView"
|
||||
x:Uid="NavView"
|
||||
Grid.Row="1"
|
||||
CompactModeThresholdWidth="Infinity"
|
||||
DataContext="{x:Bind Model}"
|
||||
ExpandedModeThresholdWidth="Infinity"
|
||||
IsBackButtonVisible="Collapsed"
|
||||
IsPaneToggleButtonVisible="{x:Bind Model.IsAlwaysOnTop, Converter={StaticResource BooleanNegationConverter}, Mode=OneWay}"
|
||||
IsSettingsVisible="False"
|
||||
ItemInvoked="OnNavItemInvoked"
|
||||
Loaded="OnNavLoaded"
|
||||
MenuItemsSource="{x:Bind CreateUIElementsForCategories(Model.Categories), Mode=OneWay}"
|
||||
OpenPaneLength="{StaticResource SplitViewOpenPaneLength}"
|
||||
PaneClosed="OnNavPaneClosed"
|
||||
PaneOpened="OnNavPaneOpened"
|
||||
PaneOpening="OnNavPaneOpening"
|
||||
SelectionChanged="OnNavSelectionChanged"
|
||||
TabIndex="1"
|
||||
UseSystemFocusVisuals="True"
|
||||
IsEnabled="{x:Bind Model.IsAlwaysOnTop, Converter={StaticResource BooleanNegationConverter}, Mode=OneWay}"
|
||||
x:Load="False">
|
||||
|
||||
<muxc:NavigationView.PaneFooter>
|
||||
<muxc:NavigationViewItem x:Name="AboutButton"
|
||||
x:Uid="AboutButton"
|
||||
Style="{StaticResource NavViewItemStyle}"
|
||||
KeyDown="OnAboutButtonKeyDown"
|
||||
Tapped="OnAboutButtonClick">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph=""/>
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<FlyoutBase.AttachedFlyout>
|
||||
<Flyout x:Name="AboutPageFlyout"
|
||||
x:Uid="AboutPageFlyout"
|
||||
Closed="OnAboutFlyoutClosed"
|
||||
FlyoutPresenterStyle="{StaticResource AboutFlyoutPresenterStyle}"
|
||||
Opened="OnAboutFlyoutOpened">
|
||||
<local:AboutFlyout x:Name="AboutPage" x:Load="False"/>
|
||||
</Flyout>
|
||||
</FlyoutBase.AttachedFlyout>
|
||||
</muxc:NavigationViewItem>
|
||||
</muxc:NavigationView.PaneFooter>
|
||||
</muxc:NavigationView>
|
||||
</Grid>
|
||||
</Page>
|
584
src/Calculator/Views/MainPage.xaml.cs
Normal file
584
src/Calculator/Views/MainPage.xaml.cs
Normal file
|
@ -0,0 +1,584 @@
|
|||
using CalculatorApp.Common;
|
||||
using CalculatorApp.Common.Automation;
|
||||
using CalculatorApp.Converters;
|
||||
using CalculatorApp.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.ViewManagement;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Automation;
|
||||
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.Navigation;
|
||||
using MUXC = Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
m_model = new ViewModel.ApplicationViewModel();
|
||||
InitializeComponent();
|
||||
|
||||
KeyboardShortcutManager.Initialize();
|
||||
|
||||
Application.Current.Suspending += App_Suspending;
|
||||
m_model.PropertyChanged += OnAppPropertyChanged;
|
||||
m_accessibilitySettings = new AccessibilitySettings();
|
||||
|
||||
// CSHARP_MIGRAION: TODO: find another implementation for C#
|
||||
//double sizeInInches = 0.0;
|
||||
|
||||
//if (SUCCEEDED(GetIntegratedDisplaySize(&sizeInInches)))
|
||||
//{
|
||||
// if (sizeInInches < 7.0) // If device's display size (diagonal length) is less than 7 inches then keep the calc always in Portrait mode only
|
||||
// {
|
||||
// DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait | DisplayOrientations.PortraitFlipped;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public CalculatorApp.ViewModel.ApplicationViewModel Model
|
||||
{
|
||||
get => m_model;
|
||||
}
|
||||
|
||||
public void UnregisterEventHandlers()
|
||||
{
|
||||
Window.Current.SizeChanged -= WindowSizeChanged;
|
||||
m_accessibilitySettings.HighContrastChanged -= OnHighContrastChanged;
|
||||
|
||||
if (m_calculator != null)
|
||||
{
|
||||
m_calculator.UnregisterEventHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDefaultFocus()
|
||||
{
|
||||
if (m_calculator != null && m_calculator.Visibility == Visibility.Visible)
|
||||
{
|
||||
m_calculator.SetDefaultFocus();
|
||||
}
|
||||
if (m_dateCalculator != null && m_dateCalculator.Visibility == Visibility.Visible)
|
||||
{
|
||||
m_dateCalculator.SetDefaultFocus();
|
||||
}
|
||||
if (m_graphingCalculator != null && m_graphingCalculator.Visibility == Visibility.Visible)
|
||||
{
|
||||
m_graphingCalculator.SetDefaultFocus();
|
||||
}
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//if (m_converter != null && m_converter.Visibility == Visibility.Visible)
|
||||
//{
|
||||
// m_converter.SetDefaultFocus();
|
||||
//}
|
||||
}
|
||||
public void SetHeaderAutomationName()
|
||||
{
|
||||
ViewMode mode = m_model.Mode;
|
||||
var resProvider = AppResourceProvider.GetInstance();
|
||||
|
||||
string name;
|
||||
if (NavCategory.IsDateCalculatorViewMode(mode))
|
||||
{
|
||||
name = resProvider.GetResourceString("HeaderAutomationName_Date");
|
||||
}
|
||||
else
|
||||
{
|
||||
string full = string.Empty;
|
||||
if (NavCategory.IsCalculatorViewMode(mode) || NavCategory.IsGraphingCalculatorViewMode(mode))
|
||||
{
|
||||
full = resProvider.GetResourceString("HeaderAutomationName_Calculator");
|
||||
}
|
||||
else if (NavCategory.IsConverterViewMode(mode))
|
||||
{
|
||||
full = resProvider.GetResourceString("HeaderAutomationName_Converter");
|
||||
}
|
||||
name = LocalizationStringUtil.GetLocalizedString(full, m_model.CategoryName);
|
||||
}
|
||||
|
||||
AutomationProperties.SetName(Header, name);
|
||||
}
|
||||
|
||||
public ObservableCollection<object> CreateUIElementsForCategories(IObservableVector<NavCategoryGroup> categories)
|
||||
{
|
||||
var menuCategories = new ObservableCollection<object>(); // CSHARP_MIGRATION: TODO: Check if ObservableCollection fits here
|
||||
|
||||
foreach (var group in categories)
|
||||
{
|
||||
menuCategories.Add(CreateNavViewHeaderFromGroup(group));
|
||||
|
||||
foreach (var category in group.Categories)
|
||||
{
|
||||
menuCategories.Add(CreateNavViewItemFromCategory(category));
|
||||
}
|
||||
}
|
||||
|
||||
return menuCategories;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewMode initialMode = ViewMode.Standard;
|
||||
if (e.Parameter != null)
|
||||
{
|
||||
string stringParameter = (e.Parameter as string);
|
||||
if (!string.IsNullOrEmpty(stringParameter))
|
||||
{
|
||||
initialMode = (ViewMode)Convert.ToInt32(stringParameter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
|
||||
if (localSettings.Values.ContainsKey(ApplicationViewModel.ModePropertyName))
|
||||
{
|
||||
initialMode = NavCategory.Deserialize(localSettings.Values[ApplicationViewModel.ModePropertyName]);
|
||||
}
|
||||
}
|
||||
|
||||
m_model.Initialize(initialMode);
|
||||
}
|
||||
|
||||
private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
|
||||
{
|
||||
// We don't use layout aware page's view states, we have our own
|
||||
UpdateViewState();
|
||||
}
|
||||
|
||||
private void OnAppPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
string propertyName = e.PropertyName;
|
||||
if (propertyName == ApplicationViewModel.ModePropertyName)
|
||||
{
|
||||
ViewMode newValue = m_model.Mode;
|
||||
ViewMode previousMode = m_model.PreviousMode;
|
||||
|
||||
KeyboardShortcutManager.DisableShortcuts(false);
|
||||
|
||||
if (newValue == ViewMode.Standard)
|
||||
{
|
||||
EnsureCalculator();
|
||||
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = true;
|
||||
m_calculator.AnimateCalculator(NavCategory.IsConverterViewMode(previousMode));
|
||||
m_model.CalculatorViewModel.HistoryVM.ReloadHistory(newValue);
|
||||
}
|
||||
else if (newValue == ViewMode.Scientific)
|
||||
{
|
||||
EnsureCalculator();
|
||||
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = true;
|
||||
if (m_model.PreviousMode != ViewMode.Scientific)
|
||||
{
|
||||
m_calculator.AnimateCalculator(NavCategory.IsConverterViewMode(previousMode));
|
||||
}
|
||||
|
||||
m_model.CalculatorViewModel.HistoryVM.ReloadHistory(newValue);
|
||||
}
|
||||
else if (newValue == ViewMode.Programmer)
|
||||
{
|
||||
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = false;
|
||||
EnsureCalculator();
|
||||
if (m_model.PreviousMode != ViewMode.Programmer)
|
||||
{
|
||||
m_calculator.AnimateCalculator(NavCategory.IsConverterViewMode(previousMode));
|
||||
}
|
||||
}
|
||||
else if (NavCategory.IsDateCalculatorViewMode(newValue))
|
||||
{
|
||||
if (m_model.CalculatorViewModel != null)
|
||||
{
|
||||
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = false;
|
||||
}
|
||||
EnsureDateCalculator();
|
||||
}
|
||||
else if (newValue == ViewMode.Graphing)
|
||||
{
|
||||
EnsureGraphingCalculator();
|
||||
KeyboardShortcutManager.DisableShortcuts(true);
|
||||
}
|
||||
else if (NavCategory.IsConverterViewMode(newValue))
|
||||
{
|
||||
if (m_model.CalculatorViewModel != null)
|
||||
{
|
||||
m_model.CalculatorViewModel.HistoryVM.AreHistoryShortcutsEnabled = false;
|
||||
}
|
||||
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//EnsureConverter();
|
||||
if (!NavCategory.IsConverterViewMode(previousMode))
|
||||
{
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//m_converter.AnimateConverter();
|
||||
}
|
||||
}
|
||||
|
||||
ShowHideControls(newValue);
|
||||
|
||||
UpdateViewState();
|
||||
SetDefaultFocus();
|
||||
}
|
||||
else if (propertyName == ApplicationViewModel.CategoryNamePropertyName)
|
||||
{
|
||||
SetHeaderAutomationName();
|
||||
AnnounceCategoryName();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNavLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (NavView.SelectedItem == null)
|
||||
{
|
||||
var menuItems = ((ObservableCollection<object>)NavView.MenuItemsSource);
|
||||
var itemCount = ((int)menuItems.Count);
|
||||
var flatIndex = NavCategory.GetFlatIndex(Model.Mode);
|
||||
|
||||
if (flatIndex >= 0 && flatIndex < itemCount)
|
||||
{
|
||||
NavView.SelectedItem = menuItems[flatIndex];
|
||||
}
|
||||
}
|
||||
|
||||
var acceleratorList = new List<MyVirtualKey>();
|
||||
NavCategory.GetCategoryAcceleratorKeys(acceleratorList);
|
||||
|
||||
foreach (var accelerator in acceleratorList)
|
||||
{
|
||||
NavView.SetValue(Common.KeyboardShortcutManager.VirtualKeyAltChordProperty, accelerator);
|
||||
}
|
||||
// Special case logic for Ctrl+E accelerator for Date Calculation Mode
|
||||
NavView.SetValue(Common.KeyboardShortcutManager.VirtualKeyControlChordProperty, Common.MyVirtualKey.E);
|
||||
}
|
||||
|
||||
private void OnNavPaneOpening(MUXC.NavigationView sender, object args)
|
||||
{
|
||||
if (AboutButton != null)
|
||||
{
|
||||
FindName("AboutButton");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNavPaneOpened(MUXC.NavigationView sender, object args)
|
||||
{
|
||||
KeyboardShortcutManager.HonorShortcuts(false);
|
||||
TraceLogger.GetInstance().LogNavBarOpened();
|
||||
}
|
||||
|
||||
private void OnNavPaneClosed(MUXC.NavigationView sender, object args)
|
||||
{
|
||||
if (Model.Mode != ViewMode.Graphing)
|
||||
{
|
||||
KeyboardShortcutManager.HonorShortcuts(true);
|
||||
}
|
||||
|
||||
SetDefaultFocus();
|
||||
}
|
||||
|
||||
private void OnNavSelectionChanged(object sender, MUXC.NavigationViewSelectionChangedEventArgs e)
|
||||
{
|
||||
var item = (e.SelectedItemContainer as MUXC.NavigationViewItem);
|
||||
if (item != null)
|
||||
{
|
||||
var selectedItem = ((NavCategory)item.DataContext);
|
||||
Model.Mode = selectedItem.Mode;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNavItemInvoked(MUXC.NavigationView sender, MUXC.NavigationViewItemInvokedEventArgs e)
|
||||
{
|
||||
NavView.IsPaneOpen = false;
|
||||
}
|
||||
|
||||
private void OnAboutButtonClick(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
ShowAboutPage();
|
||||
}
|
||||
|
||||
private void OnAboutButtonKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.Key == Windows.System.VirtualKey.Space || e.Key == Windows.System.VirtualKey.Enter)
|
||||
{
|
||||
ShowAboutPage();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAboutFlyoutOpened(object sender, object e)
|
||||
{
|
||||
// Keep Ignoring Escape till the About page flyout is opened
|
||||
KeyboardShortcutManager.IgnoreEscape(false);
|
||||
KeyboardShortcutManager.HonorShortcuts(false);
|
||||
}
|
||||
|
||||
private void OnAboutFlyoutClosed(object sender, object e)
|
||||
{
|
||||
// Start Honoring Escape once the About page flyout is closed
|
||||
KeyboardShortcutManager.HonorEscape();
|
||||
KeyboardShortcutManager.HonorShortcuts(!NavView.IsPaneOpen);
|
||||
}
|
||||
|
||||
private void AlwaysOnTopButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Model.ToggleAlwaysOnTop(0, 0);
|
||||
}
|
||||
|
||||
private void TitleBarAlwaysOnTopButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var bounds = Window.Current.Bounds;
|
||||
Model.ToggleAlwaysOnTop((float)bounds.Width, (float)bounds.Height);
|
||||
}
|
||||
|
||||
private MUXC.NavigationViewItemHeader CreateNavViewHeaderFromGroup(NavCategoryGroup group)
|
||||
{
|
||||
var header = new MUXC.NavigationViewItemHeader();
|
||||
header.DataContext = group;
|
||||
|
||||
header.Content = group.Name;
|
||||
AutomationProperties.SetName(header, group.AutomationName);
|
||||
AutomationProperties.SetHeadingLevel(header, Windows.UI.Xaml.Automation.Peers.AutomationHeadingLevel.Level1);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private MUXC.NavigationViewItem CreateNavViewItemFromCategory(NavCategory category)
|
||||
{
|
||||
var item = new MUXC.NavigationViewItem();
|
||||
item.DataContext = category;
|
||||
|
||||
var icon = new FontIcon();
|
||||
icon.FontFamily = (Windows.UI.Xaml.Media.FontFamily)(App.Current.Resources["CalculatorFontFamily"]);
|
||||
icon.Glyph = category.Glyph;
|
||||
item.Icon = icon;
|
||||
|
||||
item.Content = category.Name;
|
||||
item.AccessKey = category.AccessKey;
|
||||
item.IsEnabled = category.IsEnabled;
|
||||
item.Style = (Windows.UI.Xaml.Style)(Resources["NavViewItemStyle"]);
|
||||
|
||||
AutomationProperties.SetName(item, category.AutomationName);
|
||||
AutomationProperties.SetAutomationId(item, category.AutomationId);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void ShowHideControls(ViewMode mode)
|
||||
{
|
||||
var isCalcViewMode = NavCategory.IsCalculatorViewMode(mode);
|
||||
var isDateCalcViewMode = NavCategory.IsDateCalculatorViewMode(mode);
|
||||
var isGraphingCalcViewMode = NavCategory.IsGraphingCalculatorViewMode(mode);
|
||||
var isConverterViewMode = NavCategory.IsConverterViewMode(mode);
|
||||
|
||||
if (m_calculator != null)
|
||||
{
|
||||
m_calculator.Visibility = BooleanToVisibilityConverter.Convert(isCalcViewMode);
|
||||
m_calculator.IsEnabled = isCalcViewMode;
|
||||
}
|
||||
|
||||
if (m_dateCalculator != null)
|
||||
{
|
||||
m_dateCalculator.Visibility = BooleanToVisibilityConverter.Convert(isDateCalcViewMode);
|
||||
m_dateCalculator.IsEnabled = isDateCalcViewMode;
|
||||
}
|
||||
|
||||
if (m_graphingCalculator != null)
|
||||
{
|
||||
m_graphingCalculator.Visibility = BooleanToVisibilityConverter.Convert(isGraphingCalcViewMode);
|
||||
m_graphingCalculator.IsEnabled = isGraphingCalcViewMode;
|
||||
}
|
||||
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//if (m_converter != null)
|
||||
//{
|
||||
// m_converter.Visibility = BooleanToVisibilityConverter.Convert(isConverterViewMode);
|
||||
// m_converter.IsEnabled = isConverterViewMode;
|
||||
//}
|
||||
}
|
||||
|
||||
private void UpdateViewState()
|
||||
{
|
||||
// All layout related view states are now handled only inside individual controls (standard, scientific, programmer, date, converter)
|
||||
if (NavCategory.IsConverterViewMode(m_model.Mode))
|
||||
{
|
||||
int modeIndex = NavCategory.GetIndexInGroup(m_model.Mode, CategoryGroupType.Converter);
|
||||
m_model.ConverterViewModel.CurrentCategory = m_model.ConverterViewModel.Categories[modeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePanelViewState()
|
||||
{
|
||||
if (m_calculator != null)
|
||||
{
|
||||
m_calculator.UpdatePanelViewState();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHighContrastChanged(AccessibilitySettings sender, object args)
|
||||
{
|
||||
if (Model.IsAlwaysOnTop && ActualHeight < 394)
|
||||
{
|
||||
// Sets to default always-on-top size to force re-layout
|
||||
ApplicationView.GetForCurrentView().TryResizeView(new Size(320, 394));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPageLoaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//if (!m_converter && !m_calculator && !m_dateCalculator && !m_graphingCalculator)
|
||||
if (m_calculator == null && m_dateCalculator == null && m_graphingCalculator == null)
|
||||
{
|
||||
// We have just launched into our default mode (standard calc) so ensure calc is loaded
|
||||
EnsureCalculator();
|
||||
m_model.CalculatorViewModel.IsStandard = true;
|
||||
}
|
||||
|
||||
Window.Current.SizeChanged += WindowSizeChanged;
|
||||
m_accessibilitySettings.HighContrastChanged += OnHighContrastChanged;
|
||||
UpdateViewState();
|
||||
|
||||
SetHeaderAutomationName();
|
||||
SetDefaultFocus();
|
||||
|
||||
// Delay load things later when we get a chance.
|
||||
_ = Dispatcher.RunAsync(
|
||||
CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
|
||||
{
|
||||
if (TraceLogger.GetInstance().IsWindowIdInLog(ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())))
|
||||
{
|
||||
AppLifecycleLogger.GetInstance().LaunchUIResponsive();
|
||||
AppLifecycleLogger.GetInstance().LaunchVisibleComplete();
|
||||
}
|
||||
|
||||
FindName("NavView");
|
||||
}));
|
||||
}
|
||||
|
||||
private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
|
||||
{
|
||||
if (m_model.IsAlwaysOnTop)
|
||||
{
|
||||
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
|
||||
localSettings.Values.Add(ApplicationViewModel.WidthLocalSettings, ActualWidth);
|
||||
localSettings.Values.Add(ApplicationViewModel.HeightLocalSettings, ActualHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureCalculator()
|
||||
{
|
||||
if (m_calculator == null)
|
||||
{
|
||||
// delay load calculator.
|
||||
m_calculator = new Calculator();
|
||||
m_calculator.Name = "Calculator";
|
||||
m_calculator.DataContext = m_model.CalculatorViewModel;
|
||||
Binding isStandardBinding = new Binding();
|
||||
isStandardBinding.Path = new PropertyPath("IsStandard");
|
||||
m_calculator.SetBinding(Calculator.IsStandardProperty, isStandardBinding);
|
||||
Binding isScientificBinding = new Binding();
|
||||
isScientificBinding.Path = new PropertyPath("IsScientific");
|
||||
m_calculator.SetBinding(Calculator.IsScientificProperty, isScientificBinding);
|
||||
Binding isProgramerBinding = new Binding();
|
||||
isProgramerBinding.Path = new PropertyPath("IsProgrammer");
|
||||
m_calculator.SetBinding(Calculator.IsProgrammerProperty, isProgramerBinding);
|
||||
Binding isAlwaysOnTopBinding = new Binding();
|
||||
isAlwaysOnTopBinding.Path = new PropertyPath("IsAlwaysOnTop");
|
||||
m_calculator.SetBinding(Calculator.IsAlwaysOnTopProperty, isAlwaysOnTopBinding);
|
||||
m_calculator.Style = CalculatorBaseStyle;
|
||||
|
||||
CalcHolder.Child = m_calculator;
|
||||
|
||||
// Calculator's "default" state is visible, but if we get delay loaded
|
||||
// when in converter, we should not be visible. This is not a problem for converter
|
||||
// since its default state is hidden.
|
||||
ShowHideControls(Model.Mode);
|
||||
}
|
||||
|
||||
if (m_dateCalculator != null)
|
||||
{
|
||||
m_dateCalculator.CloseCalendarFlyout();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureDateCalculator()
|
||||
{
|
||||
if (m_dateCalculator == null)
|
||||
{
|
||||
// delay loading converter
|
||||
m_dateCalculator = new DateCalculator();
|
||||
m_dateCalculator.Name = "dateCalculator";
|
||||
m_dateCalculator.DataContext = m_model.DateCalcViewModel;
|
||||
|
||||
DateCalcHolder.Child = m_dateCalculator;
|
||||
}
|
||||
|
||||
if (m_calculator != null)
|
||||
{
|
||||
m_calculator.CloseHistoryFlyout();
|
||||
m_calculator.CloseMemoryFlyout();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureGraphingCalculator()
|
||||
{
|
||||
if (m_graphingCalculator == null)
|
||||
{
|
||||
m_graphingCalculator = new GraphingCalculator();
|
||||
m_graphingCalculator.Name = "GraphingCalculator";
|
||||
m_graphingCalculator.DataContext = m_model.GraphingCalcViewModel;
|
||||
|
||||
GraphingCalcHolder.Child = m_graphingCalculator;
|
||||
}
|
||||
}
|
||||
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//private void EnsureConverter()
|
||||
//{
|
||||
// if (!m_converter)
|
||||
// {
|
||||
// // delay loading converter
|
||||
// m_converter = new CalculatorApp.UnitConverter();
|
||||
// m_converter.Name = "unitConverter";
|
||||
// m_converter.DataContext = m_model.ConverterViewModel;
|
||||
// m_converter.Style = UnitConverterBaseStyle;
|
||||
// ConverterHolder.Child = m_converter;
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
private void ShowAboutPage()
|
||||
{
|
||||
if (AboutPage != null)
|
||||
{
|
||||
FindName("AboutPage");
|
||||
}
|
||||
|
||||
FlyoutBase.ShowAttachedFlyout(AboutButton);
|
||||
}
|
||||
|
||||
private void AnnounceCategoryName()
|
||||
{
|
||||
string categoryName = AutomationProperties.GetName(Header);
|
||||
NarratorAnnouncement announcement = CalculatorAnnouncement.GetCategoryNameChangedAnnouncement(categoryName);
|
||||
NarratorNotifier.Announce(announcement);
|
||||
}
|
||||
|
||||
private CalculatorApp.Calculator m_calculator;
|
||||
private GraphingCalculator m_graphingCalculator;
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
//private CalculatorApp.UnitConverter m_converter;
|
||||
private CalculatorApp.DateCalculator m_dateCalculator;
|
||||
private CalculatorApp.ViewModel.ApplicationViewModel m_model;
|
||||
private Windows.UI.ViewManagement.AccessibilitySettings m_accessibilitySettings;
|
||||
}
|
||||
}
|
135
src/Calculator/Views/Memory.xaml
Normal file
135
src/Calculator/Views/Memory.xaml
Normal file
|
@ -0,0 +1,135 @@
|
|||
<UserControl x:Class="CalculatorApp.Memory"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:common="using:CalculatorApp.Common"
|
||||
xmlns:controls="using:CalculatorApp.Controls"
|
||||
xmlns:converters="using:CalculatorApp.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:CalculatorApp.ViewModel"
|
||||
x:Name="MemoryList"
|
||||
FlowDirection="LeftToRight"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/>
|
||||
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
|
||||
|
||||
<MenuFlyout x:Name="MemoryContextMenu">
|
||||
<MenuFlyoutItem x:Uid="ClearMemoryMenuItem" Click="OnClearMenuItemClicked">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph=""/>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem x:Uid="MemPlusMenuItem" Click="OnMemoryAddMenuItemClicked">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph=""/>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem x:Uid="MemMinusMenuItem" Click="OnMemorySubtractMenuItemClicked">
|
||||
<MenuFlyoutItem.Icon>
|
||||
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph=""/>
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
</MenuFlyout>
|
||||
|
||||
<DataTemplate x:Key="MemoryItemTemplate" x:DataType="model:MemoryItemViewModel">
|
||||
<local:MemoryListItem Model="{x:Bind Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
<Style x:Key="MemoryItemContainerStyle"
|
||||
BasedOn="{StaticResource HistoryMemoryItemContainerStyle}"
|
||||
TargetType="ListViewItem">
|
||||
<Setter Property="Margin" Value="0,0,0,8"/>
|
||||
<Setter Property="ContextFlyout" Value="{StaticResource MemoryContextMenu}"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="LayoutGrid">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="{Binding RowHeight, ElementName=MemoryList, Mode=OneWay}"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="ErrorVisualStates">
|
||||
<VisualState x:Name="NoErrorLayout"/>
|
||||
<VisualState x:Name="ErrorLayout">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="MemoryListView.IsEnabled" Value="False"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup>
|
||||
<VisualState x:Name="DockedLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="560"/>
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="MemoryPanel.(Grid.Row)" Value="0"/>
|
||||
<Setter Target="MemoryPanel.(Grid.RowSpan)" Value="2"/>
|
||||
<Setter Target="MemoryListView.Padding" Value="0"/>
|
||||
<Setter Target="BackgroundShade.Visibility" Value="Collapsed"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DefaultLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Border x:Name="BackgroundShade"
|
||||
Grid.Row="1"
|
||||
Margin="0,-1,0,0"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
|
||||
BorderThickness="{ThemeResource HighContrastThicknessTop}"/>
|
||||
<Grid x:Name="MemoryPanel" Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock x:Name="MemoryPaneEmpty"
|
||||
x:Uid="MemoryPaneEmpty"
|
||||
Margin="16,14,24,0"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
FontWeight="SemiLight"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding IsMemoryEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
<ListView x:Name="MemoryListView"
|
||||
Padding="0,12,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
IsItemClickEnabled="true"
|
||||
ItemClick="MemoryListItemClick"
|
||||
ItemContainerStyle="{ThemeResource MemoryItemContainerStyle}"
|
||||
ItemTemplate="{ThemeResource MemoryItemTemplate}"
|
||||
ItemsSource="{x:Bind Model.MemorizedNumbers, Mode=OneWay}"
|
||||
SelectionMode="None"
|
||||
TabIndex="0"
|
||||
Visibility="{x:Bind Model.IsMemoryEmpty, Mode=OneWay, Converter={StaticResource BooleanToVisibilityNegationConverter}}">
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition/>
|
||||
<ContentThemeTransition/>
|
||||
<ReorderThemeTransition/>
|
||||
</TransitionCollection>
|
||||
</ListView.ItemContainerTransitions>
|
||||
</ListView>
|
||||
<Button x:Name="ClearMemory"
|
||||
x:Uid="ClearMemory"
|
||||
Grid.Row="1"
|
||||
Style="{ThemeResource ClearAllHistoryMemoryButtonStyle}"
|
||||
AutomationProperties.AutomationId="ClearMemory"
|
||||
Command="{x:Bind Model.ClearMemoryCommand, Mode=OneWay}"
|
||||
Content=""
|
||||
Visibility="{x:Bind Model.IsMemoryEmpty, Mode=OneWay, Converter={StaticResource BooleanToVisibilityNegationConverter}}"/>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
104
src/Calculator/Views/Memory.xaml.cs
Normal file
104
src/Calculator/Views/Memory.xaml.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using CalculatorApp.Common;
|
||||
using CalculatorApp.ViewModel;
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public sealed partial class Memory : UserControl
|
||||
{
|
||||
public Memory()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
MemoryPaneEmpty.FlowDirection = LocalizationService.GetInstance().GetFlowDirection();
|
||||
}
|
||||
|
||||
public CalculatorApp.ViewModel.StandardCalculatorViewModel Model
|
||||
{
|
||||
get { return (CalculatorApp.ViewModel.StandardCalculatorViewModel)GetValue(ModelProperty); }
|
||||
set { SetValue(ModelProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Model. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty ModelProperty =
|
||||
DependencyProperty.Register(nameof(Model), typeof(CalculatorApp.ViewModel.StandardCalculatorViewModel), typeof(Memory), new PropertyMetadata(default(CalculatorApp.ViewModel.StandardCalculatorViewModel)));
|
||||
|
||||
public GridLength RowHeight
|
||||
{
|
||||
get { return (GridLength)GetValue(RowHeightProperty); }
|
||||
set { SetValue(RowHeightProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for RowHeight. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty RowHeightProperty =
|
||||
DependencyProperty.Register(nameof(RowHeight), typeof(GridLength), typeof(Memory), new PropertyMetadata(default(GridLength)));
|
||||
|
||||
public bool IsErrorVisualState
|
||||
{
|
||||
get => m_isErrorVisualState;
|
||||
set
|
||||
{
|
||||
if (m_isErrorVisualState != value)
|
||||
{
|
||||
m_isErrorVisualState = value;
|
||||
string newState = m_isErrorVisualState ? "ErrorLayout" : "NoErrorLayout";
|
||||
VisualStateManager.GoToState(this, newState, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Windows.Foundation.Rect m_visibleBounds;
|
||||
private Windows.Foundation.Rect m_coreBounds;
|
||||
private bool m_isErrorVisualState = false;
|
||||
|
||||
private void MemoryListItemClick(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
MemoryItemViewModel memorySlot = ((MemoryItemViewModel)e.ClickedItem);
|
||||
|
||||
// In case the memory list is clicked and enter is pressed,
|
||||
// On Item clicked event gets fired and e->ClickedItem is Null.
|
||||
if (memorySlot != null)
|
||||
{
|
||||
Model.OnMemoryItemPressed(memorySlot.Position);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClearMenuItemClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var memoryItem = GetMemoryItemForCurrentFlyout();
|
||||
if (memoryItem != null)
|
||||
{
|
||||
memoryItem.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMemoryAddMenuItemClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var memoryItem = GetMemoryItemForCurrentFlyout();
|
||||
if (memoryItem != null)
|
||||
{
|
||||
memoryItem.MemoryAdd();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMemorySubtractMenuItemClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var memoryItem = GetMemoryItemForCurrentFlyout();
|
||||
if (memoryItem != null)
|
||||
{
|
||||
memoryItem.MemorySubtract();
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryItemViewModel GetMemoryItemForCurrentFlyout()
|
||||
{
|
||||
var listViewItem = MemoryContextMenu.Target;
|
||||
return (MemoryListView.ItemFromContainer(listViewItem) as MemoryItemViewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
97
src/Calculator/Views/MemoryListItem.xaml
Normal file
97
src/Calculator/Views/MemoryListItem.xaml
Normal file
|
@ -0,0 +1,97 @@
|
|||
<UserControl x:Class="CalculatorApp.MemoryListItem"
|
||||
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"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
FlowDirection="LeftToRight"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<muxc:FontIconSource x:Key="MemClearGlyph"
|
||||
FontFamily="{StaticResource CalculatorFontFamily}"
|
||||
Glyph=""/>
|
||||
<muxc:FontIconSource x:Key="MemPlusGlyph"
|
||||
FontFamily="{StaticResource CalculatorFontFamily}"
|
||||
Glyph=""/>
|
||||
<muxc:FontIconSource x:Key="MemMinusGlyph"
|
||||
FontFamily="{StaticResource CalculatorFontFamily}"
|
||||
Glyph=""/>
|
||||
|
||||
<muxc:SwipeItems x:Key="MemorySwipeItems" Mode="Reveal">
|
||||
<muxc:SwipeItem x:Uid="ClearMemorySwipeItem"
|
||||
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
|
||||
IconSource="{StaticResource MemClearGlyph}"
|
||||
Invoked="OnClearSwipeInvoked"/>
|
||||
<muxc:SwipeItem x:Uid="MemPlusSwipeItem"
|
||||
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
|
||||
IconSource="{StaticResource MemPlusGlyph}"
|
||||
Invoked="OnMemoryAddSwipeInvoked"/>
|
||||
<muxc:SwipeItem x:Uid="MemMinusSwipeItem"
|
||||
Background="{ThemeResource SystemControlBackgroundAccentBrush}"
|
||||
IconSource="{StaticResource MemMinusGlyph}"
|
||||
Invoked="OnMemorySubtractSwipeInvoked"/>
|
||||
</muxc:SwipeItems>
|
||||
</UserControl.Resources>
|
||||
|
||||
<muxc:SwipeControl RightItems="{StaticResource MemorySwipeItems}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="HoverStates">
|
||||
<VisualState x:Name="MemoryButtonsVisible">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="MemoryHoverButtons.Opacity" Value="1"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MemoryButtonsHidden"/>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Grid Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Margin="0,2,14,0"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{ThemeResource TitleTextBlockStyle}"
|
||||
FontWeight="SemiBold"
|
||||
AutomationProperties.AutomationId="MemoryItemValue"
|
||||
FlowDirection="LeftToRight"
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind Model.Value, Mode=OneWay}"
|
||||
TextAlignment="Right"
|
||||
TextReadingOrder="DetectFromContent"
|
||||
TextWrapping="Wrap"/>
|
||||
<Grid x:Name="MemoryHoverButtons"
|
||||
Grid.Row="1"
|
||||
Margin="0,0,10,2"
|
||||
HorizontalAlignment="Right"
|
||||
Opacity="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button x:Uid="ClearMemoryItemButton"
|
||||
Style="{StaticResource MemoryHoverButtonStyle}"
|
||||
Background="{ThemeResource SystemControlBackgroundAltMediumHighBrush}"
|
||||
AutomationProperties.AutomationId="MClearButton"
|
||||
Click="OnClearButtonClicked"
|
||||
Content="MC"/>
|
||||
<Button x:Uid="MemPlusItem"
|
||||
Grid.Column="1"
|
||||
Margin="0"
|
||||
Style="{StaticResource MemoryHoverButtonStyle}"
|
||||
Background="{ThemeResource SystemControlBackgroundAltMediumHighBrush}"
|
||||
AutomationProperties.AutomationId="MAddButton"
|
||||
Click="OnMemoryAddButtonClicked"
|
||||
Content="M+"/>
|
||||
<Button x:Uid="MemMinusItem"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource MemoryHoverButtonStyle}"
|
||||
Background="{ThemeResource SystemControlBackgroundAltMediumHighBrush}"
|
||||
AutomationProperties.AutomationId="MSubButton"
|
||||
Click="OnMemorySubtractButtonClicked"
|
||||
Content="M-"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</muxc:SwipeControl>
|
||||
</UserControl>
|
76
src/Calculator/Views/MemoryListItem.xaml.cs
Normal file
76
src/Calculator/Views/MemoryListItem.xaml.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
[Windows.Foundation.Metadata.WebHostHidden]
|
||||
public sealed partial class MemoryListItem : UserControl
|
||||
{
|
||||
public MemoryListItem()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public CalculatorApp.ViewModel.MemoryItemViewModel Model
|
||||
{
|
||||
get { return (CalculatorApp.ViewModel.MemoryItemViewModel)GetValue(ModelProperty); }
|
||||
set { SetValue(ModelProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Model. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty ModelProperty =
|
||||
DependencyProperty.Register(nameof(Model), typeof(CalculatorApp.ViewModel.MemoryItemViewModel), typeof(MemoryListItem), new PropertyMetadata(default(CalculatorApp.ViewModel.MemoryItemViewModel)));
|
||||
|
||||
protected override void OnPointerEntered(Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
base.OnPointerEntered(e);
|
||||
|
||||
// Only show hover buttons when the user is using mouse or pen.
|
||||
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse
|
||||
|| e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "MemoryButtonsVisible", true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPointerExited(Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
base.OnPointerExited(e);
|
||||
|
||||
VisualStateManager.GoToState(this, "MemoryButtonsHidden", true);
|
||||
}
|
||||
|
||||
private void OnMemoryAddButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Model.MemoryAdd();
|
||||
}
|
||||
|
||||
private void OnClearButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Model.Clear();
|
||||
}
|
||||
private void OnMemorySubtractButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Model.MemorySubtract();
|
||||
}
|
||||
|
||||
private void OnClearSwipeInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs e)
|
||||
{
|
||||
Model.Clear();
|
||||
}
|
||||
|
||||
private void OnMemoryAddSwipeInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs e)
|
||||
{
|
||||
Model.MemoryAdd();
|
||||
}
|
||||
|
||||
private void OnMemorySubtractSwipeInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs e)
|
||||
{
|
||||
Model.MemorySubtract();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
120
src/Calculator/Views/NumberPad.xaml
Normal file
120
src/Calculator/Views/NumberPad.xaml
Normal file
|
@ -0,0 +1,120 @@
|
|||
<UserControl x:Class="CalculatorApp.NumberPad"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:common="using:CalculatorApp.Common"
|
||||
xmlns:controls="using:CalculatorApp.Controls"
|
||||
xmlns:converters="using:CalculatorApp.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Name="ControlRoot"
|
||||
d:DesignHeight="315"
|
||||
d:DesignWidth="235"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid x:Name="Root">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="ErrorVisualStates">
|
||||
<VisualState x:Name="NoErrorLayout"/>
|
||||
<VisualState x:Name="ErrorLayout">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="DecimalSeparatorButton.IsEnabled" Value="false"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<controls:CalculatorButton x:Name="Num0Button"
|
||||
x:Uid="num0Button"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num0Button"
|
||||
ButtonId="Zero"/>
|
||||
<controls:CalculatorButton x:Name="Num1Button"
|
||||
x:Uid="num1Button"
|
||||
Grid.Row="2"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num1Button"
|
||||
ButtonId="One"/>
|
||||
<controls:CalculatorButton x:Name="Num2Button"
|
||||
x:Uid="num2Button"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num2Button"
|
||||
ButtonId="Two"/>
|
||||
<controls:CalculatorButton x:Name="Num3Button"
|
||||
x:Uid="num3Button"
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num3Button"
|
||||
ButtonId="Three"/>
|
||||
<controls:CalculatorButton x:Name="Num4Button"
|
||||
x:Uid="num4Button"
|
||||
Grid.Row="1"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num4Button"
|
||||
ButtonId="Four"/>
|
||||
<controls:CalculatorButton x:Name="Num5Button"
|
||||
x:Uid="num5Button"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num5Button"
|
||||
ButtonId="Five"/>
|
||||
<controls:CalculatorButton x:Name="Num6Button"
|
||||
x:Uid="num6Button"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num6Button"
|
||||
ButtonId="Six"/>
|
||||
<controls:CalculatorButton x:Name="Num7Button"
|
||||
x:Uid="num7Button"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num7Button"
|
||||
ButtonId="Seven"/>
|
||||
<controls:CalculatorButton x:Name="Num8Button"
|
||||
x:Uid="num8Button"
|
||||
Grid.Column="1"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num8Button"
|
||||
ButtonId="Eight"/>
|
||||
<controls:CalculatorButton x:Name="Num9Button"
|
||||
x:Uid="num9Button"
|
||||
Grid.Column="2"
|
||||
Style="{x:Bind Path=ButtonStyle, Mode=OneWay}"
|
||||
AutomationProperties.AutomationId="num9Button"
|
||||
ButtonId="Nine"/>
|
||||
|
||||
<!--
|
||||
This is the only button in all of the app that should ever have a explicit reference to KeyboardShortcutManager in Xaml
|
||||
this is needed because we need to have at least 1 reference from Xaml so the right metadata is generated for the
|
||||
KeyboardShortcutManager class, otherwise the Xaml will stop parsing and the app won't boot therefore:
|
||||
DO NOT REMOVE the common:KeyboardShortcutManager.Character from this element, it's value will be overwritten by the
|
||||
string coming from the RESW file
|
||||
-->
|
||||
<controls:CalculatorButton x:Name="DecimalSeparatorButton"
|
||||
x:Uid="decimalSeparatorButton"
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Style="{Binding ElementName=ControlRoot, Path=ButtonStyle}"
|
||||
common:KeyboardShortcutManager.Character="."
|
||||
AutomationProperties.AutomationId="decimalSeparatorButton"
|
||||
ButtonId="Decimal"
|
||||
IsEnabled="{Binding IsDecimalEnabled}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
102
src/Calculator/Views/NumberPad.xaml.cs
Normal file
102
src/Calculator/Views/NumberPad.xaml.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using CalculatorApp.Common;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public sealed partial class NumberPad : UserControl
|
||||
{
|
||||
public NumberPad()
|
||||
{
|
||||
m_isErrorVisualState = false;
|
||||
InitializeComponent();
|
||||
|
||||
var localizationSettings = LocalizationSettings.GetInstance();
|
||||
|
||||
DecimalSeparatorButton.Content = localizationSettings.GetDecimalSeparator();
|
||||
Num0Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('0');
|
||||
Num1Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('1');
|
||||
Num2Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('2');
|
||||
Num3Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('3');
|
||||
Num4Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('4');
|
||||
Num5Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('5');
|
||||
Num6Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('6');
|
||||
Num7Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('7');
|
||||
Num8Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('8');
|
||||
Num9Button.Content = localizationSettings.GetDigitSymbolFromEnUsDigit('9');
|
||||
}
|
||||
|
||||
public Windows.UI.Xaml.Style ButtonStyle
|
||||
{
|
||||
get { return (Windows.UI.Xaml.Style)GetValue(ButtonStyleProperty); }
|
||||
set { SetValue(ButtonStyleProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for ButtonStyle. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty ButtonStyleProperty =
|
||||
DependencyProperty.Register(nameof(ButtonStyle), typeof(Windows.UI.Xaml.Style), typeof(NumberPad), new PropertyMetadata(default(Windows.UI.Xaml.Style)));
|
||||
|
||||
public CalculatorApp.Common.NumberBase CurrentRadixType
|
||||
{
|
||||
get { return (CalculatorApp.Common.NumberBase)GetValue(CurrentRadixTypeProperty); }
|
||||
set { SetValue(CurrentRadixTypeProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for CurrentRadixType. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty CurrentRadixTypeProperty =
|
||||
DependencyProperty.Register(nameof(CurrentRadixType), typeof(CalculatorApp.Common.NumberBase), typeof(NumberPad), new PropertyMetadata(CalculatorApp.Common.NumberBase.DecBase, (sender, args) =>
|
||||
{
|
||||
var self = (NumberPad)sender;
|
||||
self.OnCurrentRadixTypePropertyChanged((NumberBase)args.OldValue, (NumberBase)args.NewValue);
|
||||
}));
|
||||
|
||||
public bool IsErrorVisualState
|
||||
{
|
||||
get { return m_isErrorVisualState; }
|
||||
set
|
||||
{
|
||||
if (m_isErrorVisualState != value)
|
||||
{
|
||||
m_isErrorVisualState = value;
|
||||
string newState = m_isErrorVisualState ? "ErrorLayout" : "NoErrorLayout";
|
||||
VisualStateManager.GoToState(this, newState, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCurrentRadixTypePropertyChanged(NumberBase oldValue, NumberBase newValue)
|
||||
{
|
||||
Num0Button.IsEnabled = true;
|
||||
Num1Button.IsEnabled = true;
|
||||
Num2Button.IsEnabled = true;
|
||||
Num3Button.IsEnabled = true;
|
||||
Num4Button.IsEnabled = true;
|
||||
Num5Button.IsEnabled = true;
|
||||
Num6Button.IsEnabled = true;
|
||||
Num7Button.IsEnabled = true;
|
||||
Num8Button.IsEnabled = true;
|
||||
Num9Button.IsEnabled = true;
|
||||
|
||||
if (newValue == NumberBase.BinBase)
|
||||
{
|
||||
Num2Button.IsEnabled = false;
|
||||
Num3Button.IsEnabled = false;
|
||||
Num4Button.IsEnabled = false;
|
||||
Num5Button.IsEnabled = false;
|
||||
Num6Button.IsEnabled = false;
|
||||
Num7Button.IsEnabled = false;
|
||||
Num8Button.IsEnabled = false;
|
||||
Num9Button.IsEnabled = false;
|
||||
}
|
||||
else if (newValue == NumberBase.OctBase)
|
||||
{
|
||||
Num8Button.IsEnabled = false;
|
||||
Num9Button.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_isErrorVisualState;
|
||||
}
|
||||
}
|
35
src/Calculator/Views/OperatorsPanel.xaml
Normal file
35
src/Calculator/Views/OperatorsPanel.xaml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<UserControl x:Class="CalculatorApp.OperatorsPanel"
|
||||
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"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="315"
|
||||
d:DesignWidth="235"
|
||||
UseLayoutRounding="False"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<local:CalculatorStandardOperators x:Name="StandardOperators"
|
||||
TabIndex="17"
|
||||
IsEnabled="{x:Bind Model.IsStandard, Mode=OneWay}"
|
||||
x:Load="{x:Bind Model.IsStandard, Mode=OneWay}"/>
|
||||
|
||||
<local:CalculatorScientificOperators x:Name="ScientificOperators"
|
||||
TabIndex="16"
|
||||
Visibility="{x:Bind Model.IsScientific, Mode=OneWay}"
|
||||
IsEnabled="{x:Bind Model.IsScientific, Mode=OneWay}"
|
||||
x:Load="False"/>
|
||||
|
||||
<local:CalculatorProgrammerBitFlipPanel x:Name="BitFlipPanel"
|
||||
Visibility="{x:Bind Model.IsBinaryBitFlippingEnabled, Mode=OneWay}"
|
||||
IsEnabled="{x:Bind Model.IsBinaryBitFlippingEnabled, Mode=OneWay}"
|
||||
x:Load="False"/>
|
||||
|
||||
<local:CalculatorProgrammerRadixOperators x:Name="ProgrammerRadixOperators"
|
||||
TabIndex="16"
|
||||
Visibility="{x:Bind Model.AreProgrammerRadixOperatorsVisible, Mode=OneWay}"
|
||||
IsEnabled="{x:Bind Model.IsProgrammer, Mode=OneWay}"
|
||||
x:Load="False"/>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
99
src/Calculator/Views/OperatorsPanel.xaml.cs
Normal file
99
src/Calculator/Views/OperatorsPanel.xaml.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
[Windows.Foundation.Metadata.WebHostHidden]
|
||||
public sealed partial class OperatorsPanel : UserControl
|
||||
{
|
||||
public CalculatorApp.ViewModel.StandardCalculatorViewModel Model
|
||||
{
|
||||
get => (CalculatorApp.ViewModel.StandardCalculatorViewModel)DataContext;
|
||||
}
|
||||
|
||||
public OperatorsPanel()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public bool IsBitFlipChecked
|
||||
{
|
||||
get { return (bool)GetValue(IsBitFlipCheckedProperty); }
|
||||
set { SetValue(IsBitFlipCheckedProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for IsBitFlipChecked. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty IsBitFlipCheckedProperty =
|
||||
DependencyProperty.Register(nameof(IsBitFlipChecked), typeof(bool), typeof(OperatorsPanel), new PropertyMetadata(default(bool), (sender, args) =>
|
||||
{
|
||||
var self = (OperatorsPanel)sender;
|
||||
self.OnIsBitFlipCheckedPropertyChanged((bool)args.OldValue, (bool)args.NewValue);
|
||||
}));
|
||||
|
||||
public bool IsErrorVisualState
|
||||
{
|
||||
get { return (bool)GetValue(IsErrorVisualStateProperty); }
|
||||
set { SetValue(IsErrorVisualStateProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for IsErrorVisualState. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty IsErrorVisualStateProperty =
|
||||
DependencyProperty.Register(nameof(IsErrorVisualState), typeof(bool), typeof(OperatorsPanel), new PropertyMetadata(default(bool), (sender, args) =>
|
||||
{
|
||||
var self = (OperatorsPanel)sender;
|
||||
self.OnIsErrorVisualStatePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
|
||||
}));
|
||||
|
||||
void OnIsBitFlipCheckedPropertyChanged(bool oldValue, bool newValue)
|
||||
{
|
||||
if (newValue)
|
||||
{
|
||||
EnsureProgrammerBitFlipPanel();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsErrorVisualStatePropertyChanged(bool oldValue, bool newValue)
|
||||
{
|
||||
if (Model.IsStandard)
|
||||
{
|
||||
StandardOperators.IsErrorVisualState = newValue;
|
||||
}
|
||||
else if (Model.IsScientific)
|
||||
{
|
||||
ScientificOperators.IsErrorVisualState = newValue;
|
||||
}
|
||||
else if (Model.IsProgrammer)
|
||||
{
|
||||
ProgrammerRadixOperators.IsErrorVisualState = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureScientificOps()
|
||||
{
|
||||
if (ScientificOperators == null)
|
||||
{
|
||||
FindName("ScientificOperators");
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureProgrammerRadixOps()
|
||||
{
|
||||
if (ProgrammerRadixOperators == null)
|
||||
{
|
||||
FindName("ProgrammerRadixOperators");
|
||||
}
|
||||
|
||||
ProgrammerRadixOperators.checkDefaultBitShift();
|
||||
}
|
||||
|
||||
private void EnsureProgrammerBitFlipPanel()
|
||||
{
|
||||
if (BitFlipPanel == null)
|
||||
{
|
||||
this.FindName("BitFlipPanel");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
145
src/Calculator/Views/StateTriggers/AspectRatioTrigger.cs
Normal file
145
src/Calculator/Views/StateTriggers/AspectRatioTrigger.cs
Normal file
|
@ -0,0 +1,145 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/* The AspectRatioTrigger class is a custom trigger for use with a VisualState. The trigger is designed to fire when the
|
||||
height/width of the source FrameworkElement is greater than a specified threshold. In order to be a flexible class, it
|
||||
exposes a NumeratorAspect property that can be either Height or Width. The property chosen will be the numerator when
|
||||
calculating the ratio between the two properties. Additionally, users can configure whether the ratio must be strictly
|
||||
greater than the threshold, or if equal should be considered acceptable for the state to trigger. */
|
||||
|
||||
using System;
|
||||
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace CalculatorApp.Views.StateTriggers
|
||||
{
|
||||
public enum Aspect
|
||||
{
|
||||
Height,
|
||||
Width
|
||||
};
|
||||
|
||||
public sealed class AspectRatioTrigger : Windows.UI.Xaml.StateTriggerBase
|
||||
{
|
||||
public AspectRatioTrigger()
|
||||
{
|
||||
SetActive(false);
|
||||
}
|
||||
|
||||
/* The source for which this class will respond to size changed events. */
|
||||
public FrameworkElement Source
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register(nameof(Source), typeof(FrameworkElement), typeof(AspectRatioTrigger), new PropertyMetadata(default(FrameworkElement), (sender, args) =>
|
||||
{
|
||||
var self = (AspectRatioTrigger)sender;
|
||||
self.OnSourcePropertyChanged((FrameworkElement)args.OldValue, (FrameworkElement)args.NewValue);
|
||||
}));
|
||||
|
||||
/* Either Height or Width. The property will determine which aspect is used as the numerator when calculating
|
||||
the aspect ratio. */
|
||||
public Aspect NumeratorAspect
|
||||
{
|
||||
get { return (Aspect)GetValue(NumeratorAspectProperty); }
|
||||
set { SetValue(NumeratorAspectProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for NumeratorAspect This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty NumeratorAspectProperty =
|
||||
DependencyProperty.Register(nameof(NumeratorAspect), typeof(Aspect), typeof(AspectRatioTrigger), new PropertyMetadata(default(Aspect)));
|
||||
|
||||
/* The threshold that will cause the trigger to fire when the aspect ratio exceeds this value. */
|
||||
public double Threshold
|
||||
{
|
||||
get { return (double)GetValue(ThresholdProperty); }
|
||||
set { SetValue(ThresholdProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Threshold. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty ThresholdProperty =
|
||||
DependencyProperty.Register(nameof(Threshold), typeof(double), typeof(AspectRatioTrigger), new PropertyMetadata(0.0));
|
||||
|
||||
/* If true, the trigger will fire if the aspect ratio is greater than or equal to the threshold. */
|
||||
public bool ActiveIfEqual
|
||||
{
|
||||
get { return (bool)GetValue(ActiveIfEqualProperty); }
|
||||
set { SetValue(ActiveIfEqualProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for ActiveEqual. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty ActiveIfEqualProperty =
|
||||
DependencyProperty.Register(nameof(ActiveIfEqual), typeof(bool), typeof(AspectRatioTrigger), new PropertyMetadata(false));
|
||||
|
||||
~AspectRatioTrigger()
|
||||
{
|
||||
UnregisterSizeChanged(Source);
|
||||
}
|
||||
|
||||
private void OnSourcePropertyChanged(FrameworkElement oldValue, FrameworkElement newValue)
|
||||
{
|
||||
UnregisterSizeChanged(oldValue);
|
||||
RegisterSizeChanged(newValue);
|
||||
}
|
||||
|
||||
private void RegisterSizeChanged(FrameworkElement element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (element != Source)
|
||||
{
|
||||
UnregisterSizeChanged(Source);
|
||||
}
|
||||
|
||||
element.SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
private void UnregisterSizeChanged(FrameworkElement element)
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
element.SizeChanged -= OnSizeChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
UpdateIsActive(e.NewSize);
|
||||
}
|
||||
|
||||
private void UpdateIsActive(Size sourceSize)
|
||||
{
|
||||
double numerator, denominator;
|
||||
if (NumeratorAspect == Aspect.Height)
|
||||
{
|
||||
numerator = sourceSize.Height;
|
||||
denominator = sourceSize.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
numerator = sourceSize.Width;
|
||||
denominator = sourceSize.Height;
|
||||
}
|
||||
|
||||
bool isActive = false;
|
||||
if (denominator > 0)
|
||||
{
|
||||
double ratio = numerator / denominator;
|
||||
double threshold = Math.Abs(Threshold);
|
||||
|
||||
isActive = ((ratio > threshold) || (ActiveIfEqual && (ratio == threshold)));
|
||||
}
|
||||
|
||||
SetActive(isActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<UserControl x:Class="CalculatorApp.CalculatorProgrammerDisplayPanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:common="using:CalculatorApp.Common"
|
||||
xmlns:controls="using:CalculatorApp.Controls"
|
||||
xmlns:converters="using:CalculatorApp.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Margin="3,0,0,0"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="ProgrammerDisplay">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*" MaxWidth="160"/>
|
||||
<ColumnDefinition Width="0.01*"/>
|
||||
<ColumnDefinition Width="1*" MaxWidth="80"/>
|
||||
<ColumnDefinition Width="1*" MaxWidth="80"/>
|
||||
<ColumnDefinition Width="1*" MaxWidth="80"/>
|
||||
<ColumnDefinition Width="1*" MaxWidth="80"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="Layouts">
|
||||
<VisualState x:Name="MinSizeLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowHeight="{StaticResource AppMinWindowHeight}" MinWindowWidth="{StaticResource AppMinWindowWidth}"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DefaultLayout">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ErrorVisualStates">
|
||||
<VisualState x:Name="NoErrorLayout"/>
|
||||
<VisualState x:Name="ErrorLayout">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="QwordButton.IsEnabled" Value="False"/>
|
||||
<Setter Target="DwordButton.IsEnabled" Value="False"/>
|
||||
<Setter Target="WordButton.IsEnabled" Value="False"/>
|
||||
<Setter Target="ByteButton.IsEnabled" Value="False"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Grid x:Uid="InputModeSelectionGroup"
|
||||
Grid.Column="0"
|
||||
AutomationProperties.HeadingLevel="Level1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" MaxWidth="80"/>
|
||||
<ColumnDefinition Width="1*" MaxWidth="80"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<RadioButton x:Name="FullKeypad"
|
||||
x:Uid="fullKeypad"
|
||||
Style="{StaticResource ProgKeypadRadioButtonStyle}"
|
||||
AutomationProperties.AutomationId="fullKeypad"
|
||||
Content=""
|
||||
IsChecked="{x:Bind Model.IsBitFlipChecked, Converter={StaticResource BooleanNegationConverter}, Mode=TwoWay}"/>
|
||||
<RadioButton x:Name="BitFlip"
|
||||
x:Uid="bitFlip"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource ProgKeypadRadioButtonStyle}"
|
||||
AutomationProperties.AutomationId="bitFlip"
|
||||
Content=""
|
||||
IsChecked="{x:Bind Model.IsBitFlipChecked, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
|
||||
<Button x:Name="QwordButton"
|
||||
x:Uid="qwordButton"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="7"
|
||||
Style="{StaticResource ProgWordSizeButtonStyle}"
|
||||
AutomationProperties.AutomationId="qwordButton"
|
||||
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
|
||||
CommandParameter="0"
|
||||
Content="QWORD"/>
|
||||
<Button x:Name="DwordButton"
|
||||
x:Uid="dwordButton"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="7"
|
||||
Style="{StaticResource ProgWordSizeButtonStyle}"
|
||||
AutomationProperties.AutomationId="dwordButton"
|
||||
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
|
||||
CommandParameter="1"
|
||||
Content="DWORD"
|
||||
Visibility="Collapsed"/>
|
||||
<Button x:Name="WordButton"
|
||||
x:Uid="wordButton"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="7"
|
||||
Style="{StaticResource ProgWordSizeButtonStyle}"
|
||||
AutomationProperties.AutomationId="wordButton"
|
||||
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
|
||||
CommandParameter="2"
|
||||
Content="WORD"
|
||||
Visibility="Collapsed"/>
|
||||
<Button x:Name="ByteButton"
|
||||
x:Uid="byteButton"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="7"
|
||||
Style="{StaticResource ProgWordSizeButtonStyle}"
|
||||
AutomationProperties.AutomationId="byteButton"
|
||||
Command="{x:Bind BitLengthButtonPressed, Mode=OneTime}"
|
||||
CommandParameter="3"
|
||||
Content="BYTE"
|
||||
Visibility="Collapsed"/>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,97 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
[Windows.Foundation.Metadata.WebHostHidden]
|
||||
public sealed partial class CalculatorProgrammerDisplayPanel : UserControl
|
||||
{
|
||||
public ICommand BitLengthButtonPressed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (donotuse_BitLengthButtonPressed == null)
|
||||
{
|
||||
donotuse_BitLengthButtonPressed =
|
||||
new Common.DelegateCommand<CalculatorProgrammerDisplayPanel>(this, OnBitLengthButtonPressed);
|
||||
}
|
||||
return donotuse_BitLengthButtonPressed;
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand donotuse_BitLengthButtonPressed;
|
||||
|
||||
public ViewModel.StandardCalculatorViewModel Model
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(DataContext as ViewModel.StandardCalculatorViewModel != null, "static_cast result must NOT be null");
|
||||
return DataContext as ViewModel.StandardCalculatorViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsErrorVisualState
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_isErrorVisualState;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_isErrorVisualState != value)
|
||||
{
|
||||
m_isErrorVisualState = value;
|
||||
string newState = m_isErrorVisualState ? "ErrorLayout" : "NoErrorLayout";
|
||||
VisualStateManager.GoToState(this, newState, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CalculatorProgrammerDisplayPanel()
|
||||
{
|
||||
m_isErrorVisualState = false;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnBitLengthButtonPressed(object parameter)
|
||||
{
|
||||
string buttonId = parameter.ToString();
|
||||
|
||||
QwordButton.Visibility = Visibility.Collapsed;
|
||||
DwordButton.Visibility = Visibility.Collapsed;
|
||||
WordButton.Visibility = Visibility.Collapsed;
|
||||
ByteButton.Visibility = Visibility.Collapsed;
|
||||
if (buttonId == "0")
|
||||
{
|
||||
Model.ValueBitLength = Common.BitLength.BitLengthDWord;
|
||||
DwordButton.Visibility = Visibility.Visible;
|
||||
DwordButton.Focus(FocusState.Programmatic);
|
||||
}
|
||||
else if (buttonId == "1")
|
||||
{
|
||||
Model.ValueBitLength = Common.BitLength.BitLengthWord;
|
||||
WordButton.Visibility = Visibility.Visible;
|
||||
WordButton.Focus(FocusState.Programmatic);
|
||||
}
|
||||
else if (buttonId == "2")
|
||||
{
|
||||
Model.ValueBitLength = Common.BitLength.BitLengthByte;
|
||||
ByteButton.Visibility = Visibility.Visible;
|
||||
ByteButton.Focus(FocusState.Programmatic);
|
||||
}
|
||||
else if (buttonId == "3")
|
||||
{
|
||||
Model.ValueBitLength = Common.BitLength.BitLengthQWord;
|
||||
QwordButton.Visibility = Visibility.Visible;
|
||||
QwordButton.Focus(FocusState.Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_isErrorVisualState;
|
||||
}
|
||||
}
|
115
src/Calculator/Views/StateTriggers/ControlSizeTrigger.cs
Normal file
115
src/Calculator/Views/StateTriggers/ControlSizeTrigger.cs
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace CalculatorApp.Views.StateTriggers
|
||||
{
|
||||
public sealed class ControlSizeTrigger : Windows.UI.Xaml.StateTriggerBase
|
||||
{
|
||||
public ControlSizeTrigger()
|
||||
{
|
||||
SetActive(false);
|
||||
}
|
||||
|
||||
public FrameworkElement Source
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(SourceProperty); }
|
||||
set { SetValue(SourceProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register(nameof(Source), typeof(FrameworkElement), typeof(ControlSizeTrigger), new PropertyMetadata(default(FrameworkElement), (sender, args) =>
|
||||
{
|
||||
var self = (ControlSizeTrigger)sender;
|
||||
self.OnSourcePropertyChanged((FrameworkElement)args.OldValue, (FrameworkElement)args.NewValue);
|
||||
}));
|
||||
|
||||
public double MinHeight
|
||||
{
|
||||
get { return (double)GetValue(MinHeightProperty); }
|
||||
set { SetValue(MinHeightProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for MinHeight. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty MinHeightProperty =
|
||||
DependencyProperty.Register(nameof(MinHeight), typeof(double), typeof(ControlSizeTrigger), new PropertyMetadata(-1));
|
||||
|
||||
public double MinWidth
|
||||
{
|
||||
get { return (double)GetValue(MinWidthProperty); }
|
||||
set { SetValue(MinWidthProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for MinWidth. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty MinWidthProperty =
|
||||
DependencyProperty.Register(nameof(MinWidth), typeof(double), typeof(ControlSizeTrigger), new PropertyMetadata(-1));
|
||||
|
||||
~ControlSizeTrigger()
|
||||
{
|
||||
// CSHARP_MIGRATION: TODO:
|
||||
// finalization will happen on a finalizer's thread.
|
||||
// to prevent crashing the entire app, switch to UI thread to do unregistering work
|
||||
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
UnregisterSizeChanged(Source);
|
||||
})
|
||||
.AsTask()
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
private void OnSourcePropertyChanged(FrameworkElement oldValue, FrameworkElement newValue)
|
||||
{
|
||||
UnregisterSizeChanged(oldValue);
|
||||
RegisterSizeChanged(newValue);
|
||||
}
|
||||
|
||||
private void RegisterSizeChanged(FrameworkElement element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (element != Source)
|
||||
{
|
||||
UnregisterSizeChanged(Source);
|
||||
}
|
||||
|
||||
element.SizeChanged += OnSizeChanged;
|
||||
UpdateIsActive(element.RenderSize);
|
||||
}
|
||||
|
||||
private void UnregisterSizeChanged(FrameworkElement element)
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
element.SizeChanged -= OnSizeChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
UpdateIsActive(e.NewSize);
|
||||
}
|
||||
|
||||
private void UpdateIsActive(Size sourceSize)
|
||||
{
|
||||
if (MinHeight >= 0)
|
||||
{
|
||||
SetActive(sourceSize.Height >= MinHeight && (MinWidth < 0 || sourceSize.Width >= MinWidth));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetActive(MinWidth >= 0 && sourceSize.Width >= MinWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
107
src/Calculator/Views/SupplementaryResults.xaml
Normal file
107
src/Calculator/Views/SupplementaryResults.xaml
Normal file
|
@ -0,0 +1,107 @@
|
|||
<UserControl x:Class="CalculatorApp.SupplementaryResults"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:common="using:CalculatorApp.Common"
|
||||
xmlns:controls="using:CalculatorApp.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:designdata="using:CalculatorApp.DesignData"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:CalculatorApp.ViewModel"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Name="SupplementaryValueTemplate" x:DataType="vm:SupplementaryResult">
|
||||
<StackPanel Margin="0" Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,4,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
AutomationProperties.AutomationId="SupplementaryResultValue"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Value}"/>
|
||||
<TextBlock Margin="0,0,16,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
AutomationProperties.AutomationId="SupplementaryResultUnit"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Unit.Abbreviation}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<local:DelighterUnitToStyleConverter x:Key="DelighterUnitStyleConverter"/>
|
||||
<DataTemplate x:Name="DelighterValueTemplate" x:DataType="vm:SupplementaryResult">
|
||||
<StackPanel Margin="0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Bottom"
|
||||
Style="{Binding Unit, Converter={StaticResource DelighterUnitStyleConverter}, Mode=OneTime}"
|
||||
AutomationProperties.AutomationId="DelighterResultGlyph"/>
|
||||
<TextBlock Margin="-2,0,4,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
AutomationProperties.AutomationId="DelighterResultValue"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Value}"/>
|
||||
<TextBlock Margin="0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
AutomationProperties.AutomationId="DelighterResultUnit"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Unit.Abbreviation}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<local:SupplementaryResultDataTemplateSelector x:Key="ResultTemplateSelector"
|
||||
DelighterTemplate="{StaticResource DelighterValueTemplate}"
|
||||
RegularTemplate="{StaticResource SupplementaryValueTemplate}"/>
|
||||
|
||||
<Style x:Key="SupplementaryValuesStyle" TargetType="controls:SupplementaryItemsControl">
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:SupplementaryItemsControl">
|
||||
<ItemsPresenter/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemContainerTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<local:SupplementaryResultNoOverflowStackPanel/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="SupplementaryResultsHeader"
|
||||
Margin="0,0,0,-6"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="Also equal to"/>
|
||||
<controls:SupplementaryItemsControl x:Name="SupplementaryValues"
|
||||
MinHeight="27"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{ThemeResource SupplementaryValuesStyle}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
|
||||
ItemsSource="{x:Bind Results, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
115
src/Calculator/Views/SupplementaryResults.xaml.cs
Normal file
115
src/Calculator/Views/SupplementaryResults.xaml.cs
Normal file
|
@ -0,0 +1,115 @@
|
|||
using CalculatorApp.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public sealed class DelighterUnitToStyleConverter : Windows.UI.Xaml.Data.IValueConverter
|
||||
{
|
||||
public DelighterUnitToStyleConverter()
|
||||
{
|
||||
m_delighters = new Windows.UI.Xaml.ResourceDictionary();
|
||||
m_delighters.Source = new Uri(@"ms-appx:///Views/DelighterUnitStyles.xaml");
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
Unit unit = (Unit)value;
|
||||
Debug.Assert(unit.IsModelUnitWhimsical());
|
||||
if (!unit.IsModelUnitWhimsical())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string key = $"Unit_{unit.ModelUnitID()}";
|
||||
return (Style)m_delighters[key];
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
// We never use convert back, only one way binding supported
|
||||
Debug.Assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
private Windows.UI.Xaml.ResourceDictionary m_delighters;
|
||||
}
|
||||
|
||||
public sealed class SupplementaryResultDataTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
|
||||
{
|
||||
public SupplementaryResultDataTemplateSelector()
|
||||
{ }
|
||||
|
||||
public Windows.UI.Xaml.DataTemplate RegularTemplate
|
||||
{
|
||||
get => m_regularTemplate;
|
||||
set => m_regularTemplate = value;
|
||||
}
|
||||
|
||||
public Windows.UI.Xaml.DataTemplate DelighterTemplate
|
||||
{
|
||||
get => m_delighterTemplate;
|
||||
set => m_delighterTemplate = value;
|
||||
}
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
SupplementaryResult result = (SupplementaryResult)item;
|
||||
if (result.IsWhimsical())
|
||||
{
|
||||
return DelighterTemplate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RegularTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
private Windows.UI.Xaml.DataTemplate m_regularTemplate;
|
||||
private Windows.UI.Xaml.DataTemplate m_delighterTemplate;
|
||||
}
|
||||
|
||||
public sealed class SupplementaryResultNoOverflowStackPanel : CalculatorApp.Controls.HorizontalNoOverflowStackPanel
|
||||
{
|
||||
protected override bool ShouldPrioritizeLastItem()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var lastChild = Children[Children.Count - 1] as FrameworkElement;
|
||||
if (lastChild == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var suppResult = lastChild.DataContext as SupplementaryResult;
|
||||
return suppResult == null ? false : suppResult.IsWhimsical();
|
||||
}
|
||||
}
|
||||
|
||||
[Windows.Foundation.Metadata.WebHostHidden]
|
||||
public sealed partial class SupplementaryResults : UserControl
|
||||
{
|
||||
public SupplementaryResults()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public IEnumerable<ViewModel.SupplementaryResult> Results
|
||||
{
|
||||
get { return (IEnumerable<ViewModel.SupplementaryResult>)GetValue(ResultsProperty); }
|
||||
set { SetValue(ResultsProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Results. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty ResultsProperty =
|
||||
DependencyProperty.Register(nameof(Results), typeof(IEnumerable<ViewModel.SupplementaryResult>), typeof(SupplementaryResult), new PropertyMetadata(null));
|
||||
}
|
||||
}
|
60
src/Calculator/Views/TitleBar.xaml
Normal file
60
src/Calculator/Views/TitleBar.xaml
Normal file
|
@ -0,0 +1,60 @@
|
|||
<UserControl x:Class="CalculatorApp.TitleBar"
|
||||
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"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<Grid x:Name="LayoutRoot"
|
||||
Height="32"
|
||||
HorizontalAlignment="Stretch">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="WindowFocusStates">
|
||||
<VisualState x:Name="WindowFocused"/>
|
||||
<VisualState x:Name="WindowNotFocused">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="AppName.Foreground" Value="{ThemeResource SystemControlForegroundChromeDisabledLowBrush}"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="AOTStates">
|
||||
<VisualState x:Name="AOTNormalState"/>
|
||||
<VisualState x:Name="AOTMiniState">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="AppName.Visibility" Value="Collapsed"/>
|
||||
<Setter Target="ExitAlwaysOnTopButton.Visibility" Value="Visible"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Grid x:Name="BackgroundElement" Background="Transparent">
|
||||
<TextBlock x:Name="AppName"
|
||||
x:Uid="AppName"
|
||||
Margin="12,0,12,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{ThemeResource TitleBarForegroundBaseHighBrush}"
|
||||
FontSize="12"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
<Button x:Name="ExitAlwaysOnTopButton"
|
||||
x:Uid="ExitAlwaysOnTopButton"
|
||||
Width="46"
|
||||
Height="Auto"
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalContentAlignment="Center"
|
||||
Style="{ThemeResource CommandBarFlyoutEllipsisButtonStyle}"
|
||||
Background="Transparent"
|
||||
FontFamily="{StaticResource CalculatorFontFamily}"
|
||||
FontSize="14"
|
||||
FontWeight="Thin"
|
||||
AutomationProperties.AutomationId="ExitAlwaysOnTopButton"
|
||||
Click="AlwaysOnTopButton_Click"
|
||||
Content=""
|
||||
Visibility="Collapsed"
|
||||
x:Load="False">
|
||||
<Button.KeyboardAccelerators>
|
||||
<KeyboardAccelerator Key="Down" Modifiers="Menu"/>
|
||||
</Button.KeyboardAccelerators>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
209
src/Calculator/Views/TitleBar.xaml.cs
Normal file
209
src/Calculator/Views/TitleBar.xaml.cs
Normal file
|
@ -0,0 +1,209 @@
|
|||
using System;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.System.Profile;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.ViewManagement;
|
||||
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 TitleBar : UserControl
|
||||
{
|
||||
public TitleBar()
|
||||
{
|
||||
m_coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
|
||||
m_uiSettings = new UISettings();
|
||||
m_accessibilitySettings = new AccessibilitySettings();
|
||||
InitializeComponent();
|
||||
|
||||
m_coreTitleBar.ExtendViewIntoTitleBar = true;
|
||||
Window.Current.SetTitleBar(BackgroundElement);
|
||||
|
||||
Loaded += OnLoaded;
|
||||
Unloaded += OnUnloaded;
|
||||
#if IS_STORE_BUILD
|
||||
AppName.Text = AppResourceProvider.GetInstance().GetResourceString("AppName");
|
||||
|
||||
#else
|
||||
AppName.Text = AppResourceProvider.GetInstance().GetResourceString("DevAppName");
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool IsAlwaysOnTopMode
|
||||
{
|
||||
get { return (bool)GetValue(IsAlwaysOnTopModeProperty); }
|
||||
set { SetValue(IsAlwaysOnTopModeProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for IsAlwaysOnTopMode. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty IsAlwaysOnTopModeProperty =
|
||||
DependencyProperty.Register(nameof(IsAlwaysOnTopMode), typeof(bool), typeof(TitleBar), new PropertyMetadata(default(bool), (sender, args) =>
|
||||
{
|
||||
var self = (TitleBar)sender;
|
||||
self.OnIsAlwaysOnTopModePropertyChanged((bool)args.OldValue, (bool)args.NewValue);
|
||||
}));
|
||||
|
||||
public event Windows.UI.Xaml.RoutedEventHandler AlwaysOnTopClick;
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Register events
|
||||
m_coreTitleBar.IsVisibleChanged += CoreTitleBarIsVisibleChanged;
|
||||
m_coreTitleBar.LayoutMetricsChanged += CoreTitleBarLayoutMetricsChanged;
|
||||
|
||||
m_uiSettings.ColorValuesChanged += ColorValuesChanged;
|
||||
m_accessibilitySettings.HighContrastChanged += OnHighContrastChanged;
|
||||
Window.Current.Activated += OnWindowActivated;
|
||||
|
||||
// Set properties
|
||||
SetTitleBarControlColors();
|
||||
SetTitleBarHeightAndPadding();
|
||||
|
||||
// As of Windows 10 1903: when an app runs on a PC (without Tablet mode activated)
|
||||
// properties of CoreApplicationViewTitleBar aren't initialized during the first seconds after launch.
|
||||
var forceDisplay = AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Desktop"
|
||||
&& UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Mouse;
|
||||
|
||||
SetTitleBarVisibility(forceDisplay);
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Unregister events
|
||||
m_coreTitleBar.LayoutMetricsChanged -= CoreTitleBarLayoutMetricsChanged;
|
||||
m_coreTitleBar.IsVisibleChanged -= CoreTitleBarIsVisibleChanged;
|
||||
m_uiSettings.ColorValuesChanged -= ColorValuesChanged;
|
||||
m_accessibilitySettings.HighContrastChanged -= OnHighContrastChanged;
|
||||
Window.Current.Activated -= OnWindowActivated;
|
||||
}
|
||||
|
||||
private void CoreTitleBarIsVisibleChanged(CoreApplicationViewTitleBar cTitleBar, object args)
|
||||
{
|
||||
SetTitleBarVisibility(false);
|
||||
}
|
||||
|
||||
private void CoreTitleBarLayoutMetricsChanged(CoreApplicationViewTitleBar cTitleBar, object args)
|
||||
{
|
||||
SetTitleBarHeightAndPadding();
|
||||
}
|
||||
|
||||
private void SetTitleBarVisibility(bool forceDisplay)
|
||||
{
|
||||
LayoutRoot.Visibility =
|
||||
forceDisplay || m_coreTitleBar.IsVisible || IsAlwaysOnTopMode ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void SetTitleBarHeightAndPadding()
|
||||
{
|
||||
if (m_coreTitleBar.Height == 0)
|
||||
{
|
||||
// The titlebar isn't init
|
||||
return;
|
||||
}
|
||||
|
||||
double leftAddition = 0;
|
||||
double rightAddition = 0;
|
||||
|
||||
if (FlowDirection == FlowDirection.LeftToRight)
|
||||
{
|
||||
leftAddition = m_coreTitleBar.SystemOverlayLeftInset;
|
||||
rightAddition = m_coreTitleBar.SystemOverlayRightInset;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftAddition = m_coreTitleBar.SystemOverlayRightInset;
|
||||
leftAddition = m_coreTitleBar.SystemOverlayLeftInset;
|
||||
}
|
||||
|
||||
LayoutRoot.Padding = new Thickness(leftAddition, 0, rightAddition, 0);
|
||||
LayoutRoot.Height = m_coreTitleBar.Height;
|
||||
}
|
||||
|
||||
private void ColorValuesChanged(Windows.UI.ViewManagement.UISettings sender, object e)
|
||||
{
|
||||
_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() => { SetTitleBarControlColors(); }));
|
||||
}
|
||||
|
||||
private void SetTitleBarControlColors()
|
||||
{
|
||||
var applicationView = ApplicationView.GetForCurrentView();
|
||||
if (applicationView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var applicationTitleBar = applicationView.TitleBar;
|
||||
if (applicationTitleBar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_accessibilitySettings.HighContrast)
|
||||
{
|
||||
// Reset to use default colors.
|
||||
applicationTitleBar.ButtonBackgroundColor = null;
|
||||
applicationTitleBar.ButtonForegroundColor = null;
|
||||
applicationTitleBar.ButtonInactiveBackgroundColor = null;
|
||||
applicationTitleBar.ButtonInactiveForegroundColor = null;
|
||||
applicationTitleBar.ButtonHoverBackgroundColor = null;
|
||||
applicationTitleBar.ButtonHoverForegroundColor = null;
|
||||
applicationTitleBar.ButtonPressedBackgroundColor = null;
|
||||
applicationTitleBar.ButtonPressedForegroundColor = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Color bgColor = Colors.Transparent;
|
||||
Color fgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlPageTextBaseHighBrush"]).Color;
|
||||
Color inactivefgColor =
|
||||
((SolidColorBrush)Application.Current.Resources["SystemControlForegroundChromeDisabledLowBrush"]).Color;
|
||||
Color hoverbgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlBackgroundListLowBrush"]).Color;
|
||||
Color hoverfgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlForegroundBaseHighBrush"]).Color;
|
||||
Color pressedbgColor = ((SolidColorBrush)Application.Current.Resources["SystemControlBackgroundListMediumBrush"]).Color;
|
||||
Color pressedfgCoolor = ((SolidColorBrush)Application.Current.Resources["SystemControlForegroundBaseHighBrush"]).Color;
|
||||
applicationTitleBar.ButtonBackgroundColor = bgColor;
|
||||
applicationTitleBar.ButtonForegroundColor = fgColor;
|
||||
applicationTitleBar.ButtonInactiveBackgroundColor = bgColor;
|
||||
applicationTitleBar.ButtonInactiveForegroundColor = inactivefgColor;
|
||||
applicationTitleBar.ButtonHoverBackgroundColor = hoverbgColor;
|
||||
applicationTitleBar.ButtonHoverForegroundColor = hoverfgColor;
|
||||
applicationTitleBar.ButtonPressedBackgroundColor = pressedbgColor;
|
||||
applicationTitleBar.ButtonPressedForegroundColor = pressedfgCoolor;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHighContrastChanged(Windows.UI.ViewManagement.AccessibilitySettings sender, object args)
|
||||
{
|
||||
_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
|
||||
{
|
||||
SetTitleBarControlColors();
|
||||
SetTitleBarVisibility(false);
|
||||
}));
|
||||
}
|
||||
|
||||
private void OnWindowActivated(object sender, WindowActivatedEventArgs e)
|
||||
{
|
||||
VisualStateManager.GoToState(
|
||||
this, e.WindowActivationState == CoreWindowActivationState.Deactivated ? WindowNotFocused.Name : WindowFocused.Name, false);
|
||||
}
|
||||
|
||||
private void OnIsAlwaysOnTopModePropertyChanged(bool oldValue, bool newValue)
|
||||
{
|
||||
SetTitleBarVisibility(false);
|
||||
VisualStateManager.GoToState(this, newValue ? "AOTMiniState" : "AOTNormalState", false);
|
||||
}
|
||||
|
||||
private void AlwaysOnTopButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AlwaysOnTopClick(this, e);
|
||||
}
|
||||
|
||||
private Windows.ApplicationModel.Core.CoreApplicationViewTitleBar m_coreTitleBar;
|
||||
private Windows.UI.ViewManagement.UISettings m_uiSettings;
|
||||
private Windows.UI.ViewManagement.AccessibilitySettings m_accessibilitySettings;
|
||||
}
|
||||
}
|
190
src/Calculator/WindowFrameService.cs
Normal file
190
src/Calculator/WindowFrameService.cs
Normal file
|
@ -0,0 +1,190 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using CalculatorApp.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.ViewManagement;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public sealed class WindowFrameService
|
||||
{
|
||||
public Page GetCurrentPage()
|
||||
{
|
||||
return (m_frame.Content as Page);
|
||||
}
|
||||
|
||||
public void SetNewFrame(Windows.UI.Xaml.Controls.Frame frame)
|
||||
{
|
||||
Debug.Assert(frame.BackStackDepth == 0);
|
||||
m_frame = frame;
|
||||
}
|
||||
|
||||
// createdByUs means any window that we create.
|
||||
// !createdByUs means the main window
|
||||
internal static WindowFrameService CreateNewWindowFrameService(Frame viewFrame, bool createdByUs, WeakReference parent)
|
||||
{
|
||||
Debug.Assert(CoreWindow.GetForCurrentThread() != null);
|
||||
var frameService = new WindowFrameService(viewFrame, parent);
|
||||
frameService.InitializeFrameService(createdByUs);
|
||||
return frameService;
|
||||
}
|
||||
|
||||
public CoreDispatcher GetCoreDispatcher()
|
||||
{
|
||||
return m_coreDispatcher;
|
||||
}
|
||||
|
||||
public int GetViewId()
|
||||
{
|
||||
return m_viewId;
|
||||
}
|
||||
|
||||
public void RegisterOnWindowClosingHandler(Action onWindowClosingHandler)
|
||||
{
|
||||
m_onWindowClosingHandlers.Add(onWindowClosingHandler);
|
||||
}
|
||||
|
||||
public Task HandleViewRelease()
|
||||
{
|
||||
var that = this;
|
||||
|
||||
TaskCompletionSource<object> tsource = new TaskCompletionSource<object>();
|
||||
|
||||
_ = m_coreDispatcher.RunAsync(CoreDispatcherPriority.Low, new DispatchedHandler(() =>
|
||||
{
|
||||
KeyboardShortcutManager.OnWindowClosed(that.m_viewId);
|
||||
Window.Current.Content = null;
|
||||
that.InvokeWindowClosingHandlers();
|
||||
// This is to ensure InvokeWindowClosingHandlers is be done before RemoveWindowFromMap
|
||||
// If InvokeWindowClosingHandlers throws any exception we want it to crash the application
|
||||
// so we are OK not setting closingHandlersCompletedEvent in that case
|
||||
tsource.SetResult(new object());
|
||||
that.m_coreDispatcher.StopProcessEvents();
|
||||
Window.Current.Close();
|
||||
}));
|
||||
|
||||
return tsource.Task;
|
||||
}
|
||||
|
||||
// Throws InvalidArgumentException if a service is already registered with the specified id
|
||||
public void RegisterRuntimeWindowService(Type serviceId, object service)
|
||||
{
|
||||
if (TryResolveRuntimeWindowService(serviceId) != null)
|
||||
{
|
||||
throw new DuplicateNameException(serviceId + " already registered");
|
||||
}
|
||||
|
||||
m_runtimeServicesMap[serviceId.Name] = service;
|
||||
}
|
||||
|
||||
// Returns false if no service was registered with the specified id
|
||||
public bool RemoveRuntimeWindowService(Type serviceId)
|
||||
{
|
||||
return m_runtimeServicesMap.Remove(serviceId.Name);
|
||||
}
|
||||
|
||||
// Throws InvalidArgumentException if no service is registered with the specified id
|
||||
public object ResolveRuntimeWindowService(Type serviceId)
|
||||
{
|
||||
var service = TryResolveRuntimeWindowService(serviceId);
|
||||
|
||||
if (service != null)
|
||||
{
|
||||
return service;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new EntryPointNotFoundException(serviceId.Name + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
public Frame GetFrame()
|
||||
{
|
||||
return m_frame;
|
||||
}
|
||||
|
||||
public void InvokeWindowClosingHandlers()
|
||||
{
|
||||
// Should be called only once just before we kill the window.
|
||||
foreach (var handler in m_onWindowClosingHandlers)
|
||||
{
|
||||
handler();
|
||||
}
|
||||
m_onWindowClosingHandlers.Clear();
|
||||
}
|
||||
|
||||
private WindowFrameService(Frame frame, WeakReference parent)
|
||||
{
|
||||
m_currentWindow = CoreWindow.GetForCurrentThread();
|
||||
m_coreDispatcher = m_currentWindow.Dispatcher;
|
||||
m_frame = frame;
|
||||
m_parent = parent;
|
||||
m_viewId = ApplicationView.GetApplicationViewIdForWindow(m_currentWindow);
|
||||
}
|
||||
|
||||
private void InitializeFrameService(bool createdByUs)
|
||||
{
|
||||
Debug.Assert(createdByUs == (!CoreApplication.GetCurrentView().IsHosted && !CoreApplication.GetCurrentView().IsMain));
|
||||
if (createdByUs)
|
||||
{
|
||||
ApplicationView.GetForCurrentView().Consolidated += OnConsolidated;
|
||||
}
|
||||
else
|
||||
{
|
||||
CoreWindow.GetForCurrentThread().Closed += OnClosed;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConsolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs e)
|
||||
{
|
||||
TraceLogger.GetInstance().DecreaseWindowCount();
|
||||
if (m_parent.IsAlive)
|
||||
{
|
||||
var parent = m_parent.Target as App;
|
||||
parent.RemoveWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClosed(CoreWindow sender, CoreWindowEventArgs args)
|
||||
{
|
||||
if (m_parent.IsAlive)
|
||||
{
|
||||
var parent = m_parent.Target as App;
|
||||
parent.RemoveSecondaryWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns nullptr if no service is registered with the specified id
|
||||
private object TryResolveRuntimeWindowService(Type serviceId)
|
||||
{
|
||||
object retval;
|
||||
if (m_runtimeServicesMap.TryGetValue(serviceId.Name, out retval))
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Windows.UI.Core.CoreWindow m_currentWindow;
|
||||
private Windows.UI.Core.CoreDispatcher m_coreDispatcher;
|
||||
private Windows.UI.Xaml.Controls.Frame m_frame;
|
||||
private int m_viewId;
|
||||
private WeakReference m_parent;
|
||||
|
||||
private Dictionary<string, object> m_runtimeServicesMap = new Dictionary<string, object>();
|
||||
private List<Action> m_onWindowClosingHandlers = new List<Action>();
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue