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