// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once #include "CalcManager/ExpressionCommandInterface.h" #include "DelegateCommand.h" // Utility macros to make Models easier to write // generates a member variable called m_ #define PROPERTY_R(t, n) \ property t n \ { \ t get() \ { \ return m_##n; \ } \ \ private: \ void set(t value) \ { \ m_##n = value; \ } \ } \ \ private: \ t m_##n; \ \ public: #define PROPERTY_RW(t, n) \ property t n \ { \ t get() \ { \ return m_##n; \ } \ void set(t value) \ { \ m_##n = value; \ } \ } \ \ private: \ t m_##n; \ \ public: #define OBSERVABLE_PROPERTY_R(t, n) \ property t n \ { \ t get() \ { \ return m_##n; \ } \ \ private: \ void set(t value) \ { \ if (m_##n != value) \ { \ m_##n = value; \ RaisePropertyChanged(L#n); \ } \ } \ } \ \ private: \ t m_##n; \ \ public: #define OBSERVABLE_PROPERTY_RW(t, n) \ property t n \ { \ t get() \ { \ return m_##n; \ } \ void set(t value) \ { \ if (m_##n != value) \ { \ m_##n = value; \ RaisePropertyChanged(L#n); \ } \ } \ } \ \ private: \ t m_##n; \ \ public: #define OBSERVABLE_NAMED_PROPERTY_R(t, n) \ OBSERVABLE_PROPERTY_R(t, n) \ internal: \ static property Platform::String ^ n##PropertyName \ { \ Platform::String ^ get() { return Platform::StringReference(L#n); } \ } \ \ public: #define OBSERVABLE_NAMED_PROPERTY_RW(t, n) \ OBSERVABLE_PROPERTY_RW(t, n) \ internal: \ static property Platform::String ^ n##PropertyName \ { \ Platform::String ^ get() { return Platform::StringReference(L#n); } \ } \ \ public: #define OBSERVABLE_PROPERTY_FIELD(n) m_##n // This variant of the observable object is for objects that don't want to react to property changes #ifndef UNIT_TESTS #define OBSERVABLE_OBJECT() \ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ internal: \ void RaisePropertyChanged(Platform::String ^ p) \ { \ PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); \ } \ \ public: #else #define OBSERVABLE_OBJECT() \ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ internal: \ void RaisePropertyChanged(Platform::String ^ p) \ { \ } \ \ public: #endif // The callback specified in the macro is a method in the class that will be called every time the object changes // the callback is supposed to be have a single parameter of type Platform::String^ #ifndef UNIT_TESTS #define OBSERVABLE_OBJECT_CALLBACK(c) \ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ internal: \ void RaisePropertyChanged(Platform::String ^ p) \ { \ PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); \ c(p); \ } \ \ public: #else #define OBSERVABLE_OBJECT_CALLBACK(c) \ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \ internal: \ void RaisePropertyChanged(Platform::String ^ p) \ { \ c(p); \ } \ \ public: #endif // The variable member generated by this macro should not be used in the class code, use the // property getter instead. #define COMMAND_FOR_METHOD(p, m) \ property Windows::UI::Xaml::Input::ICommand^ p {\ Windows::UI::Xaml::Input::ICommand^ get() {\ if (!donotuse_##p) {\ donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\ } return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; \ \ public: #define DEPENDENCY_PROPERTY_DECLARATION(t, n) \ property t n \ { \ t get() \ { \ return safe_cast(GetValue(s_##n##Property)); \ } \ void set(t value) \ { \ SetValue(s_##n##Property, value); \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##n##Property; \ \ private: // Utilities for DependencyProperties namespace Utils { namespace Details { template struct IsRefClass { static const bool value = __is_ref_class(T); }; template struct RemoveHat { typedef T type; }; template struct RemoveHat { typedef T type; }; template typename std::enable_if::value, T ^>::type MakeDefault() { return nullptr; } template typename std::enable_if::value, T>::type MakeDefault() { return T(); } // There's a bug in Xaml in which custom enums are not recognized by the property system/binding // therefore this template will determine that for enums the type to use to register the // DependencyProperty is to be Object, for everything else it will use the type // NOTE: If we are to find more types in which this is broken this template // will be specialized for those types to return Object template struct TypeToUseForDependencyProperty { typedef typename std::conditional::value, Platform::Object, T>::type type; }; } const wchar_t LRE = 0x202a; // Left-to-Right Embedding const wchar_t PDF = 0x202c; // Pop Directional Formatting const wchar_t LRO = 0x202d; // Left-to-Right Override // Regular DependencyProperty template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty( _In_ const wchar_t* const name, _In_ Windows::UI::Xaml::PropertyMetadata^ metadata) { typedef typename Details::RemoveHat::type OwnerType; typedef typename Details::RemoveHat::type ThisPropertyType; typedef typename Details::TypeToUseForDependencyProperty::type ThisDependencyPropertyType; static_assert(Details::IsRefClass::value, "The owner of a DependencyProperty must be a ref class"); return Windows::UI::Xaml::DependencyProperty::Register( Platform::StringReference(name), ThisDependencyPropertyType::typeid, // Work around bugs in Xaml by using the filtered type OwnerType::typeid, metadata); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name) { typedef typename Details::RemoveHat::type ThisPropertyType; return RegisterDependencyProperty( name, ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault())); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name, TType defaultValue) { return RegisterDependencyProperty( name, ref new Windows::UI::Xaml::PropertyMetadata(defaultValue)); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback( _In_ wchar_t const * const name, TCallback callback) { typedef typename Details::RemoveHat::type ThisPropertyType; return RegisterDependencyProperty( name, ref new Windows::UI::Xaml::PropertyMetadata( Details::MakeDefault(), ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback( _In_ wchar_t const * const name, TType defaultValue, TCallback callback) { typedef typename Details::RemoveHat::type ThisPropertyType; return RegisterDependencyProperty( name, ref new Windows::UI::Xaml::PropertyMetadata( defaultValue, ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); } // Attached DependencyProperty template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached( _In_ const wchar_t* const name, _In_ Windows::UI::Xaml::PropertyMetadata^ metadata) { typedef typename Details::RemoveHat::type OwnerType; typedef typename Details::RemoveHat::type ThisPropertyType; typedef typename Details::TypeToUseForDependencyProperty::type ThisDependencyPropertyType; static_assert(Details::IsRefClass::value, "The owner of a DependencyProperty must be a ref class"); return Windows::UI::Xaml::DependencyProperty::RegisterAttached( Platform::StringReference(name), ThisDependencyPropertyType::typeid, // Work around bugs in Xaml by using the filtered type OwnerType::typeid, metadata); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name) { typedef typename Details::RemoveHat::type ThisPropertyType; return RegisterDependencyPropertyAttached( name, ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault())); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name, TType defaultValue) { return RegisterDependencyPropertyAttached( name, ref new Windows::UI::Xaml::PropertyMetadata(defaultValue)); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback( _In_ wchar_t const * const name, TCallback callback) { typedef typename Details::RemoveHat::type ThisPropertyType; return RegisterDependencyPropertyAttached( name, ref new Windows::UI::Xaml::PropertyMetadata( Details::MakeDefault(), ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); } template Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback( _In_ wchar_t const * const name, TType defaultValue, TCallback callback) { typedef typename Details::RemoveHat::type ThisPropertyType; return RegisterDependencyPropertyAttached( name, ref new Windows::UI::Xaml::PropertyMetadata( defaultValue, ref new Windows::UI::Xaml::PropertyChangedCallback(callback))); } template void Swap(T *ref1, T *ref2) { T temp = *ref1; *ref1 = *ref2; *ref2 = temp; } void IFTPlatformException(HRESULT hr); Platform::String ^ GetStringValue(Platform::String ^ input); bool IsLastCharacterTarget(std::wstring const& input, wchar_t target); std::wstring RemoveUnwantedCharsFromString(std::wstring inputString, wchar_t* unwantedChars, unsigned int size); double GetDoubleFromWstring(std::wstring input); int GetWindowId(); void RunOnUIThreadNonblocking(std::function&& function, _In_ Windows::UI::Core::CoreDispatcher ^ currentDispatcher); void SerializeCommandsAndTokens( _In_ std::shared_ptr>> const& tokens, _In_ std::shared_ptr>> const& commands, Windows::Storage::Streams::DataWriter ^ writer); const std::shared_ptr>> DeserializeCommands(Windows::Storage::Streams::DataReader ^ reader); const std::shared_ptr>> DeserializeTokens(Windows::Storage::Streams::DataReader ^ reader); Windows::Foundation::DateTime GetUniversalSystemTime(); bool IsDateTimeOlderThan(Windows::Foundation::DateTime dateTime, const long long duration); concurrency::task WriteFileToFolder( Windows::Storage::IStorageFolder ^ folder, Platform::String ^ fileName, Platform::String ^ contents, Windows::Storage::CreationCollisionOption collisionOption); concurrency::task ReadFileFromFolder(Windows::Storage::IStorageFolder ^ folder, Platform::String ^ fileName); } // This goes into the header to define the property, in the public: section of the class #define DEPENDENCY_PROPERTY_OWNER(owner) \ private: \ typedef owner DependencyPropertiesOwner; \ \ public: // Normal DependencyProperty #define DEPENDENCY_PROPERTY(type, name) \ property type name \ { \ type get() \ { \ return safe_cast(GetValue(s_##name##Property)); \ } \ void set(type value) \ { \ SetValue(s_##name##Property, value); \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyProperty(L#name); \ } \ \ public: #define DEPENDENCY_PROPERTY_WITH_DEFAULT(type, name, defaultValue) \ property type name \ { \ type get() \ { \ return safe_cast(GetValue(s_##name##Property)); \ } \ void set(type value) \ { \ SetValue(s_##name##Property, value); \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyProperty(L#name, defaultValue); \ } \ \ public: #define DEPENDENCY_PROPERTY_WITH_CALLBACK(type, name) \ property type name \ { \ type get() \ { \ return safe_cast(GetValue(s_##name##Property)); \ } \ void set(type value) \ { \ SetValue(s_##name##Property, value); \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyPropertyWithCallback(L#name, &On##name##PropertyChangedImpl); \ } \ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ { \ auto self = safe_cast(sender); \ self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \ } \ \ public: #define DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \ property type name \ { \ type get() \ { \ return safe_cast(GetValue(s_##name##Property)); \ } \ void set(type value) \ { \ SetValue(s_##name##Property, value); \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyPropertyWithCallback(L#name, defaultValue, &On##name##PropertyChangedImpl); \ } \ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ { \ auto self = safe_cast(sender); \ self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \ } \ \ public: // Attached DependencyProperty #define DEPENDENCY_PROPERTY_ATTACHED(type, name) \ static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ { \ return safe_cast(target->GetValue(s_##name##Property)); \ } \ static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ { \ target->SetValue(s_##name##Property, value); \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyPropertyAttached(L#name); \ } \ \ public: #define DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT(type, name, defaultValue) \ static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ { \ return safe_cast(target->GetValue(s_##name##Property)); \ } \ static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ { \ target->SetValue(s_##name##Property, value); \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyPropertyAttached(L#name, defaultValue); \ } \ \ public: #define DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(type, name) \ static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ { \ return safe_cast(target->GetValue(s_##name##Property)); \ } \ static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ { \ target->SetValue(s_##name##Property, value); \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyPropertyAttachedWithCallback(L#name, &On##name##PropertyChangedImpl); \ } \ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ { \ On##name##PropertyChanged(sender, safe_cast(args->OldValue), safe_cast(args->NewValue)); \ } \ \ public: #define DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \ static type Get##name(Windows::UI::Xaml::DependencyObject ^ target) \ { \ return safe_cast(target->GetValue(s_##name##Property)); \ } \ static void Set##name(Windows::UI::Xaml::DependencyObject ^ target, type value) \ { \ target->SetValue(s_##name##Property, value); \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \ \ public: \ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \ { \ Windows::UI::Xaml::DependencyProperty ^ get() { \ assert(s_##name##Property); \ return s_##name##Property; \ } \ } \ \ private: \ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \ { \ return Utils::RegisterDependencyPropertyAttachedWithCallback(L#name, defaultValue, &On##name##PropertyChangedImpl); \ } \ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \ { \ On##name##PropertyChanged(sender, safe_cast(args->OldValue), safe_cast(args->NewValue)); \ } \ \ public: // This goes into the cpp to initialize the static variable #define DEPENDENCY_PROPERTY_INITIALIZATION(owner, name) Windows::UI::Xaml::DependencyProperty ^ owner::s_##name##Property = owner::Initialize##name##Property(); namespace CalculatorApp { template T from_cx(Platform::Object ^ from) { T to{ nullptr }; winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(to)))); return to; } }