Skip to content

Commit

Permalink
Update share output (#782)
Browse files Browse the repository at this point in the history
* fix share bugs

* PR feedback

* PR feedback and merge fix

* Fix spacing and use explicit break

* Fix extra space
  • Loading branch information
joseartrivera authored and sanderl committed Nov 19, 2019
1 parent afc1b21 commit b55659f
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 76 deletions.
65 changes: 65 additions & 0 deletions src/CalcViewModel/Common/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,71 @@ void Utils::TrimBack(wstring& value)
}).base(), value.end());
}

String^ Utils::EscapeHtmlSpecialCharacters(String^ originalString, shared_ptr<vector<wchar_t>> specialCharacters)
{
// Construct a default special characters if not provided.
if (specialCharacters == nullptr)
{
specialCharacters = make_shared<vector<wchar_t>>();
specialCharacters->push_back(L'&');
specialCharacters->push_back(L'\"');
specialCharacters->push_back(L'\'');
specialCharacters->push_back(L'<');
specialCharacters->push_back(L'>');
}

bool replaceCharacters = false;
const wchar_t* pCh;
String^ replacementString = nullptr;

// First step is scanning the string for special characters.
// If there isn't any special character, we simply return the original string
for (pCh = originalString->Data(); *pCh; pCh++)
{
if (std::find(specialCharacters->begin(), specialCharacters->end(), *pCh) != specialCharacters->end())
{
replaceCharacters = true;
break;
}
}

if (replaceCharacters)
{
// If we indeed find a special character, we step back one character (the special
// character), and we create a new string where we replace those characters one by one
pCh--;
wstringstream buffer;
buffer << wstring(originalString->Data(), pCh);

for (; *pCh; pCh++)
{
switch (*pCh)
{
case L'&':
buffer << L"&amp;";
break;
case L'\"':
buffer << L"&quot;";
break;
case L'\'':
buffer << L"&apos;";
break;
case L'<':
buffer << L"&lt;";
break;
case L'>':
buffer << L"&gt;";
break;
default:
buffer << *pCh;
}
}
replacementString = ref new String(buffer.str().c_str());
}

return replaceCharacters ? replacementString : originalString;
}

bool operator==(const Color& color1, const Color& color2)
{
return equal_to<Color>()(color1, color2);
Expand Down
1 change: 1 addition & 0 deletions src/CalcViewModel/Common/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ namespace Utils
void TrimFront(std::wstring& value);
void TrimBack(std::wstring& value);

Platform::String ^ EscapeHtmlSpecialCharacters(Platform::String ^ originalString, std::shared_ptr<std::vector<wchar_t>> specialCharacters = nullptr);

}

Expand Down
14 changes: 11 additions & 3 deletions src/Calculator/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -3507,9 +3507,17 @@
<value>Look what I graphed.</value>
<comment>Sent as part of the shared content. The title for the share.</comment>
</data>
<data name="EmptyEquationString" xml:space="preserve">
<value>Empty graph equation</value>
<comment>When sharing and one of the equations has no content this will be shown in the graph key for that equation.</comment>
<data name="EquationsShareHeader" xml:space="preserve">
<value>Equations:</value>
<comment>Header that appears over the equations section when sharing</comment>
</data>
<data name="VariablesShareHeader" xml:space="preserve">
<value>Variables:</value>
<comment>Header that appears over the variables section when sharing</comment>
</data>
<data name="GraphImageAltText" xml:space="preserve">
<value>Image of a graph with equations</value>
<comment>Alt text for the graph image when output via Share</comment>
</data>
<data name="VaiablesHeader.Text" xml:space="preserve">
<value>Variables</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@
<graphControl:Grapher Name="GraphingControl"
EquationsSource="{x:Bind ViewModel.Equations, Mode=OneWay}"
ForceProportionalAxes="True"
LosingFocus="OnLoosingFocus"
LostFocus="OnGraphLostFocus"
LosingFocus="GraphingControl_LosingFocus"
LostFocus="GraphingControl_LostFocus"
UseSystemFocusVisuals="True"
VariablesUpdated="GraphVariablesUpdated">
VariablesUpdated="GraphingControl_VariablesUpdated">
<graphControl:Grapher.Background>
<SolidColorBrush Color="White"/>
</graphControl:Grapher.Background>
Expand Down
145 changes: 80 additions & 65 deletions src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
// Licensed under the MIT License.

#include "pch.h"
#include "CalcViewModel/Common/TraceLogger.h"
#include "GraphingCalculator.xaml.h"
#include "CalcViewModel/Common/TraceLogger.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
#include "CalcViewModel/Common/KeyboardShortcutManager.h"
#include "Controls/CalculationResult.h"
#include "Calculator\Controls\EquationTextBox.h"
#include "Calculator\Views\GraphingCalculator\EquationInputArea.xaml.h"
#include "CalcManager/NumberFormattingUtils.h"
#include "Calculator/Controls/EquationTextBox.h"
#include "Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h"
#include "CalcViewModel/Common/Utils.h"

using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
using namespace CalculatorApp::ViewModel;
using namespace CalcManager::NumberFormattingUtils;
using namespace concurrency;
using namespace GraphControl;
using namespace Platform;
Expand All @@ -21,6 +25,7 @@ using namespace std;
using namespace std::chrono;
using namespace Utils;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace Windows::ApplicationModel::Resources;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Storage::Streams;
Expand Down Expand Up @@ -109,79 +114,94 @@ void CalculatorApp::GraphingCalculator::OnShareClick(Platform::Object ^ sender,
// data to be shared. We will request the current graph image from the grapher as a stream that will pass to the share request.
void GraphingCalculator::OnDataRequested(DataTransferManager ^ sender, DataRequestedEventArgs ^ args)
{
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView();
auto resourceLoader = ResourceLoader::GetForCurrentView();

try
{
// Get our title from the localized resources
auto EmptyEquationString = resourceLoader->GetString(L"EmptyEquationString");
std::wstringstream rawHtml;
std::wstringstream equationHtml;

std::wstring rawHtml = L"<p><img src='graph.png'></p>";
rawHtml << L"<p><img src='graph.png' width='600' alt='" << resourceLoader->GetString(L"GraphImageAltText")->Data() << "'></p>";

auto equations = ViewModel->Equations;
rawHtml += L"<p><table cellpadding=\"10\">";
rawHtml += L"<col width=\"20\">";
rawHtml += L"<row height=\"20\">";
for (unsigned i = 0; i < equations->Size; i++)
bool hasEquations = false;

if (equations->Size > 0)
{
auto expression = equations->GetAt(i)->Expression->Data();
auto color = equations->GetAt(i)->LineColor->Color;
equationHtml << L"<span style=\"color: rgb(68, 114, 196); font-style: bold; font-size : 13pt;\">";
equationHtml << resourceLoader->GetString(L"EquationsShareHeader")->Data();
equationHtml << L"</span>";
equationHtml << L"<table cellpadding=\"0\">";

if (equations->GetAt(i)->Expression->Length() == 0)
for (auto equation : equations)
{
expression = EmptyEquationString->Data();
auto expression = equation->Expression;
if (expression->IsEmpty())
{
continue;
}

auto color = equation->LineColor->Color;
hasEquations = true;

expression = GraphingControl->ConvertToLinear(expression);

std::wstringstream equationColorHtml;
equationColorHtml << L"color:rgb(" << color.R.ToString()->Data() << L"," << color.G.ToString()->Data() << L"," << color.B.ToString()->Data()
<< L");";

equationHtml << L"<tr><td><span style=\"line-height: 0; font-size: 24pt;" << equationColorHtml.str()
<< L"\">&#x25A0;</span></td><td><div style=\"margin: 4pt 0pt 0pt 0pt; \">";
equationHtml << EscapeHtmlSpecialCharacters(expression)->Data();
equationHtml << L"</div></td>";
}
equationHtml << L"</table>";
}

rawHtml += L"<tr>";

rawHtml += L"<td style=\"background-color:rgb(";
rawHtml += color.R.ToString()->Data();
rawHtml += L",";
rawHtml += color.G.ToString()->Data();
rawHtml += L",";
rawHtml += color.B.ToString()->Data();
rawHtml += L"); \">";
rawHtml += L"</td>";
rawHtml += L"<td>";
rawHtml += expression;
rawHtml += L"</td>";

rawHtml += L"</tr>";
if (hasEquations)
{
rawHtml << equationHtml.str();
}
rawHtml += L"</table></p>";

auto variables = ViewModel->Variables;
rawHtml += L"<p><table cellpadding=\"10\">";
rawHtml += L"<col width=\"20\">";
rawHtml += L"<row height=\"20\">";
for (unsigned i = 0; i < variables->Size; i++)
{
auto name = variables->GetAt(i)->Name;
auto value = variables->GetAt(i)->Value;

if (name->Length() >= 0)
{
rawHtml += L"<tr>";
if (variables->Size > 0)
{
auto localizedSeperator = LocalizationSettings::GetInstance().GetListSeparator() + L" ";

rawHtml += L"<td>";
rawHtml += name->Data();
rawHtml += L"</td>";
rawHtml += L"<td>";
rawHtml += std::to_wstring(value);
rawHtml += L"</td>";
rawHtml << L"<span style=\"color: rgb(68, 114, 196); font-style: bold; font-size: 13pt;\">";
rawHtml << resourceLoader->GetString(L"VariablesShareHeader")->Data();
rawHtml << L"</span><br><span>";

rawHtml += L"</tr>";
for (unsigned i = 0; i < variables->Size; i++)
{
auto name = variables->GetAt(i)->Name;
auto value = variables->GetAt(i)->Value;

rawHtml << name->Data();
rawHtml << L"=";
auto formattedValue = to_wstring(value);
TrimTrailingZeros(formattedValue);
rawHtml << formattedValue;

if (variables->Size - 1 != i)
{
rawHtml << localizedSeperator;
}
}

rawHtml << L"</span>";
}
rawHtml += L"</table></p>";

rawHtml << L"<br><br>";

// Shortcut to the request data
auto requestData = args->Request->Data;

DataPackage ^ dataPackage = ref new DataPackage();
auto html = HtmlFormatHelper::CreateHtmlFormat(ref new String(rawHtml.c_str()));
auto html = HtmlFormatHelper::CreateHtmlFormat(ref new String(rawHtml.str().c_str()));

auto titleString = resourceLoader->GetString(L"ShareActionTitle");
requestData->Properties->Title = titleString;
requestData->Properties->Title = resourceLoader->GetString(L"ShareActionTitle");

requestData->SetHtmlFormat(html);

Expand All @@ -191,26 +211,21 @@ void GraphingCalculator::OnDataRequested(DataTransferManager ^ sender, DataReque

// Set the thumbnail image (in case the share target can't handle HTML)
requestData->Properties->Thumbnail = bitmapStream;

// And the bitmap (in case the share target can't handle HTML)
requestData->SetBitmap(bitmapStream);
}
catch (Exception ^ ex)
{
TraceLogger::GetInstance().LogPlatformException(ViewMode::Graphing, __FUNCTIONW__, ex);

// Something went wrong, notify the user.
auto errorTitleString = resourceLoader->GetString(L"ShareActionErrorMessage");
auto errorOkString = resourceLoader->GetString(L"ShareActionErrorOk");
auto errDialog = ref new Windows::UI::Xaml::Controls::ContentDialog();

errDialog->Content = errorTitleString;
errDialog->CloseButtonText = errorOkString;
auto errDialog = ref new ContentDialog();
errDialog->Content = resourceLoader->GetString(L"ShareActionErrorMessage");
errDialog->CloseButtonText = resourceLoader->GetString(L"ShareActionErrorOk");
errDialog->ShowAsync();
}
}

void GraphingCalculator::GraphVariablesUpdated(Object ^, Object ^)
void GraphingCalculator::GraphingControl_VariablesUpdated(Object ^, Object ^)
{
m_viewModel->UpdateVariables(GraphingControl->Variables);
}
Expand Down Expand Up @@ -287,14 +302,14 @@ void GraphingCalculator::OnZoomResetCommand(Object ^ /* parameter */)
GraphingControl->ResetGrid();
}

void GraphingCalculator::OnActiveTracingClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e)
void GraphingCalculator::OnActiveTracingClick(Object ^ sender, RoutedEventArgs ^ e)
{
// The focus change to this button will have turned off the tracing if it was on
ActiveTracingOn = !ActiveTracingOn;
GraphingControl->ActiveTracing = ActiveTracingOn;
}

void CalculatorApp::GraphingCalculator::OnGraphLostFocus(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e)
void GraphingCalculator::GraphingControl_LostFocus(Object ^ sender, RoutedEventArgs ^ e)
{
// If the graph is losing focus while we are in active tracing we need to turn it off so we don't try to eat keys in other controls.
if (GraphingControl->ActiveTracing)
Expand All @@ -304,9 +319,9 @@ void CalculatorApp::GraphingCalculator::OnGraphLostFocus(Platform::Object ^ send
}
}

void CalculatorApp::GraphingCalculator::OnLoosingFocus(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::LosingFocusEventArgs ^ args)
void GraphingCalculator::GraphingControl_LosingFocus(UIElement ^ sender, LosingFocusEventArgs ^ args)
{
FrameworkElement ^ newFocusElement = (FrameworkElement ^) args->NewFocusedElement;
auto newFocusElement = dynamic_cast<FrameworkElement ^>(args->NewFocusedElement);
if (newFocusElement == nullptr || newFocusElement->Name == nullptr)
{
// Because clicking on the swap chain panel will try to move focus to a control that can't actually take focus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ namespace CalculatorApp
private:
void GraphingCalculator_DataContextChanged(Windows::UI::Xaml::FrameworkElement^ sender, Windows::UI::Xaml::DataContextChangedEventArgs^ args);

void GraphVariablesUpdated(Platform::Object^ sender, Object^ args);
void OnVariableChanged(Platform::Object^ sender, CalculatorApp::ViewModel::VariableChangedEventArgs args);

void TextBoxLosingFocus(Windows::UI::Xaml::Controls::TextBox^ textbox, Windows::UI::Xaml::Input::LosingFocusEventArgs^ args);
Expand All @@ -60,8 +59,9 @@ namespace CalculatorApp

void TextBoxGotFocus(Windows::UI::Xaml::Controls::TextBox^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnActiveTracingClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnGraphLostFocus(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnLoosingFocus(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::LosingFocusEventArgs ^ args);
void GraphingControl_LostFocus(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void GraphingControl_LosingFocus(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::LosingFocusEventArgs ^ args);
void GraphingControl_VariablesUpdated(Platform::Object ^ sender, Object ^ args);
void OnEquationKeyGraphFeaturesVisibilityChanged(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnKeyGraphFeaturesClosed(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
bool ActiveTracingOn;
Expand Down
Loading

0 comments on commit b55659f

Please sign in to comment.