Adding share functionality to Graphing Calculator (#601)
* Plumebd with data transfer * Getting mainpage to talk to getbitmap. moving share callbacks from mainpage to graphingcalculator * Trying to get bitmap from renderer. * work * Share worked * cleanups * Cleanups progressing * Share working, need loc for title string and user notification incase of a failure. Then add the equations key. * More cleanup, now using share icon image and resources for strings. Still need to do the graph equation key. * Change share to html based start. * Key working, with UL but going to try changing to table. * Fix a html formating error, generating a new UL for each equation. * Switched over to a table for equation key and have color block formating * Updates from PR feedback, using Graphing::IBitmap abstraction. * Update src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h Fixed Co-Authored-By: Pepe Rivera <joseartrivera@gmail.com> * PR Updates. * Add variables to the graph key. * PR Updates.
This commit is contained in:
parent
46f11c7c72
commit
c1efa3d3e3
@ -3439,6 +3439,22 @@
|
|||||||
<value>Add Equation</value>
|
<value>Add Equation</value>
|
||||||
<comment>Placeholder text for the equation input button</comment>
|
<comment>Placeholder text for the equation input button</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ShareActionErrorMessage" xml:space="preserve">
|
||||||
|
<value>Unable to share at this time.</value>
|
||||||
|
<comment>If there is an error in the sharing action will display a dialog with this text.</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ShareActionErrorOk" xml:space="preserve">
|
||||||
|
<value>OK</value>
|
||||||
|
<comment>Used on the dismiss button of the share action error dialog.</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ShareActionTitle" xml:space="preserve">
|
||||||
|
<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>
|
||||||
<data name="VaiablesHeader.Text" xml:space="preserve">
|
<data name="VaiablesHeader.Text" xml:space="preserve">
|
||||||
<value>Variables</value>
|
<value>Variables</value>
|
||||||
<comment>Header text for variables area</comment>
|
<comment>Header text for variables area</comment>
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0">
|
Grid.Column="0">
|
||||||
|
|
||||||
<graphControl:Grapher Name="GraphingControl"
|
<graphControl:Grapher Name="GraphingControl" Grid.Row="0"
|
||||||
Margin="4,7,4,4"
|
Margin="4,7,4,4"
|
||||||
EquationsSource="{x:Bind ViewModel.Equations, Mode=OneWay}"
|
EquationsSource="{x:Bind ViewModel.Equations, Mode=OneWay}"
|
||||||
ForceProportionalAxes="True"
|
ForceProportionalAxes="True"
|
||||||
@ -229,7 +229,12 @@
|
|||||||
<RowDefinition Height="3*"/>
|
<RowDefinition Height="3*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<Button x:Name="Share" Click="OnShareClick">
|
||||||
|
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph=""/>
|
||||||
|
</Button>
|
||||||
<local:EquationInputArea Grid.Row="0" Equations="{x:Bind ViewModel.Equations}"/>
|
<local:EquationInputArea Grid.Row="0" Equations="{x:Bind ViewModel.Equations}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<Grid x:Name="ButtonContainerGrid"
|
<Grid x:Name="ButtonContainerGrid"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
#include "CalcViewModel/Common/TraceLogger.h"
|
||||||
#include "GraphingCalculator.xaml.h"
|
#include "GraphingCalculator.xaml.h"
|
||||||
#include "CalcViewModel/Common/KeyboardShortcutManager.h"
|
#include "CalcViewModel/Common/KeyboardShortcutManager.h"
|
||||||
#include "Controls/CalculationResult.h"
|
#include "Controls/CalculationResult.h"
|
||||||
@ -11,27 +12,38 @@ using namespace CalculatorApp::ViewModel;
|
|||||||
using namespace concurrency;
|
using namespace concurrency;
|
||||||
using namespace GraphControl;
|
using namespace GraphControl;
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
|
using namespace Platform::Collections;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
using namespace Windows::ApplicationModel::DataTransfer;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Foundation::Collections;
|
using namespace Windows::Foundation::Collections;
|
||||||
using namespace Windows::Storage::Streams;
|
using namespace Windows::Storage::Streams;
|
||||||
using namespace Windows::System;
|
using namespace Windows::System;
|
||||||
|
using namespace Windows::UI::Core;
|
||||||
using namespace Windows::UI::Xaml;
|
using namespace Windows::UI::Xaml;
|
||||||
using namespace Windows::UI::Xaml::Data;
|
using namespace Windows::UI::Xaml::Data;
|
||||||
using namespace Windows::UI::Xaml::Controls;
|
using namespace Windows::UI::Xaml::Controls;
|
||||||
using namespace Windows::UI::Xaml::Input;
|
using namespace Windows::UI::Xaml::Input;
|
||||||
using namespace Windows::UI::Xaml::Media;
|
using namespace Windows::UI::Xaml::Media;
|
||||||
using namespace Windows::UI::Xaml::Media::Imaging;
|
using namespace Windows::UI::Xaml::Media::Imaging;
|
||||||
|
using namespace Windows::UI::Popups;
|
||||||
|
|
||||||
|
|
||||||
constexpr auto sc_ViewModelPropertyName = L"ViewModel";
|
constexpr auto sc_ViewModelPropertyName = L"ViewModel";
|
||||||
|
|
||||||
|
|
||||||
GraphingCalculator::GraphingCalculator()
|
GraphingCalculator::GraphingCalculator()
|
||||||
{
|
{
|
||||||
Equation::RegisterDependencyProperties();
|
Equation::RegisterDependencyProperties();
|
||||||
Grapher::RegisterDependencyProperties();
|
Grapher::RegisterDependencyProperties();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
DataTransferManager^ dataTransferManager = DataTransferManager::GetForCurrentView();
|
||||||
|
|
||||||
|
// Register the current control as a share source.
|
||||||
|
m_dataRequestedToken = dataTransferManager->DataRequested += ref new TypedEventHandler<DataTransferManager^, DataRequestedEventArgs^>(this, &GraphingCalculator::OnDataRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphingCalculator::GraphingCalculator_DataContextChanged(FrameworkElement^ sender, DataContextChangedEventArgs^ args)
|
void GraphingCalculator::GraphingCalculator_DataContextChanged(FrameworkElement^ sender, DataContextChangedEventArgs^ args)
|
||||||
@ -55,6 +67,118 @@ void GraphingCalculator::ViewModel::set(GraphingCalculatorViewModel^ vm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CalculatorApp::GraphingCalculator::OnShareClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||||
|
{
|
||||||
|
// Ask the OS to start a share action.
|
||||||
|
DataTransferManager::ShowShareUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
// When share is invoked (by the user or programmatically) the event handler we registered will be called to populate the data package with the
|
||||||
|
// 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();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get our title from the localized resources
|
||||||
|
auto EmptyEquationString = resourceLoader->GetString(L"EmptyEquationString");
|
||||||
|
|
||||||
|
std::wstring rawHtml = L"<p><img src='graph.png'></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++)
|
||||||
|
{
|
||||||
|
auto expression = equations->GetAt(i)->Expression->Data();
|
||||||
|
auto color = equations->GetAt(i)->LineColor;
|
||||||
|
|
||||||
|
if (equations->GetAt(i)->Expression->Length() == 0)
|
||||||
|
{
|
||||||
|
expression = EmptyEquationString->Data();
|
||||||
|
}
|
||||||
|
|
||||||
|
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>";
|
||||||
|
}
|
||||||
|
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>";
|
||||||
|
|
||||||
|
rawHtml += L"<td>";
|
||||||
|
rawHtml += name->Data();
|
||||||
|
rawHtml += L"</td>";
|
||||||
|
rawHtml += L"<td>";
|
||||||
|
rawHtml += std::to_wstring(value);
|
||||||
|
rawHtml += L"</td>";
|
||||||
|
|
||||||
|
rawHtml += L"</tr>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rawHtml += L"</table></p>";
|
||||||
|
|
||||||
|
|
||||||
|
// 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 titleString = resourceLoader->GetString(L"ShareActionTitle");
|
||||||
|
requestData->Properties->Title = titleString;
|
||||||
|
|
||||||
|
requestData->SetHtmlFormat(html);
|
||||||
|
|
||||||
|
auto bitmapStream = GraphingControl->GetGraphBitmapStream();
|
||||||
|
|
||||||
|
requestData->ResourceMap->Insert(ref new String(L"graph.png"), bitmapStream);
|
||||||
|
|
||||||
|
// 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(__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;
|
||||||
|
errDialog->ShowAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GraphingCalculator::GraphVariablesUpdated(Object^, Object^)
|
void GraphingCalculator::GraphVariablesUpdated(Object^, Object^)
|
||||||
{
|
{
|
||||||
m_viewModel->UpdateVariables(GraphingControl->Variables);
|
m_viewModel->UpdateVariables(GraphingControl->Variables);
|
||||||
|
@ -33,6 +33,15 @@ namespace CalculatorApp
|
|||||||
|
|
||||||
CalculatorApp::ViewModel::GraphingCalculatorViewModel^ m_viewModel;
|
CalculatorApp::ViewModel::GraphingCalculatorViewModel^ m_viewModel;
|
||||||
|
|
||||||
|
void OnShareClick(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Windows::Foundation::EventRegistrationToken m_dataRequestedToken;
|
||||||
|
|
||||||
|
void OnDataRequested(Windows::ApplicationModel::DataTransfer::DataTransferManager^ sender, Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs^ e);
|
||||||
|
void CommandInvokedHandler(Windows::UI::Popups::IUICommand^ command);
|
||||||
|
|
||||||
void TextBoxGotFocus(Windows::UI::Xaml::Controls::TextBox^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
void TextBoxGotFocus(Windows::UI::Xaml::Controls::TextBox^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using namespace std;
|
|||||||
using namespace Windows::Devices::Input;
|
using namespace Windows::Devices::Input;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Windows::Foundation::Collections;
|
using namespace Windows::Foundation::Collections;
|
||||||
|
using namespace Windows::Storage::Streams;
|
||||||
using namespace Windows::System;
|
using namespace Windows::System;
|
||||||
using namespace Windows::UI;
|
using namespace Windows::UI;
|
||||||
using namespace Windows::UI::Input;
|
using namespace Windows::UI::Input;
|
||||||
@ -635,4 +636,47 @@ namespace GraphControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RandomAccessStreamReference^ Grapher::GetGraphBitmapStream()
|
||||||
|
{
|
||||||
|
RandomAccessStreamReference^ outputStream;
|
||||||
|
|
||||||
|
if (m_renderMain != nullptr && m_graph != nullptr)
|
||||||
|
{
|
||||||
|
if (auto renderer = m_graph->GetRenderer())
|
||||||
|
{
|
||||||
|
std::shared_ptr < Graphing::IBitmap> BitmapOut;
|
||||||
|
bool hasSomeMissingDataOut = false;
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
hr = renderer->GetBitmap(BitmapOut, hasSomeMissingDataOut);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
// Get the raw date
|
||||||
|
std::vector<BYTE> byteVector = BitmapOut->GetData();
|
||||||
|
auto arr = ref new Array<BYTE>(&byteVector[0], (unsigned int)byteVector.size());
|
||||||
|
|
||||||
|
// create a memory stream wrapper
|
||||||
|
InMemoryRandomAccessStream^ stream = ref new InMemoryRandomAccessStream();
|
||||||
|
|
||||||
|
// Get a writer to transfer the data
|
||||||
|
auto writer = ref new DataWriter(stream->GetOutputStreamAt(0));
|
||||||
|
|
||||||
|
// write the data
|
||||||
|
writer->WriteBytes(arr);
|
||||||
|
writer->StoreAsync()->GetResults();
|
||||||
|
|
||||||
|
// Get a reference stream to return;
|
||||||
|
outputStream = RandomAccessStreamReference::CreateFromStream(stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutputDebugString(L"Grapher::GetGraphBitmapStream() unable to get graph image from renderer\r\n");
|
||||||
|
winrt::throw_hresult(hr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,5 +194,8 @@ namespace GraphControl
|
|||||||
|
|
||||||
const std::unique_ptr<Graphing::IMathSolver> m_solver;
|
const std::unique_ptr<Graphing::IMathSolver> m_solver;
|
||||||
const std::shared_ptr<Graphing::IGraph> m_graph;
|
const std::shared_ptr<Graphing::IGraph> m_graph;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Windows::Storage::Streams::RandomAccessStreamReference^ GetGraphBitmapStream();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
11
src/GraphingInterfaces/IBitmap.h
Normal file
11
src/GraphingInterfaces/IBitmap.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Graphing
|
||||||
|
{
|
||||||
|
struct IBitmap
|
||||||
|
{
|
||||||
|
virtual const std::vector<BYTE>& GetData() const = 0;
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "IBitmap.h"
|
||||||
|
|
||||||
struct ID2D1Factory;
|
struct ID2D1Factory;
|
||||||
struct ID2D1RenderTarget;
|
struct ID2D1RenderTarget;
|
||||||
@ -21,5 +22,8 @@ namespace Graphing::Renderer
|
|||||||
virtual HRESULT ChangeRange(ChangeRangeAction action) = 0;
|
virtual HRESULT ChangeRange(ChangeRangeAction action) = 0;
|
||||||
virtual HRESULT MoveRangeByRatio(double ratioX, double ratioY) = 0;
|
virtual HRESULT MoveRangeByRatio(double ratioX, double ratioY) = 0;
|
||||||
virtual HRESULT ResetRange() = 0;
|
virtual HRESULT ResetRange() = 0;
|
||||||
|
|
||||||
|
virtual HRESULT GetBitmap(std::shared_ptr<Graphing::IBitmap>& bitmapOut, bool& hasSomeMissingDataOut) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user