Passive & Active tracing (#638)

* 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.

* eod

* Passive graph value tracing working.

* Basic active tracing cursor working.

* Move active tracing from graphingcalculator to grapher to save some hops.
Also block tracking of the active tracing key's when in the EquationTextBox.

* Active tracing working, need to put button on screen for activation.

* Added active tracing control button (placeholder image)

* Eod

* Popup trace value now tracks the highlighted point.

* Popup skined

* PR Updates.

* Update certificate thumbnail so VS2019 doesn't have a build error.

* PR comments in process.

* PR Updates

* PR Updates, change tracing value to use tooltip static resource so we automatically change depending on system values.  And changed text formatting of the value to be generic (x,y) value.

* PR updates, changed how we detect who has focus so we don't eat keys when not in active tracing.

* Additional filtering for the Key Up/Down in the grapher.
This commit is contained in:
David Shoemaker
2019-10-04 12:24:43 -07:00
committed by Stephanie Anderl
parent 7864fe6413
commit 18f80a89db
12 changed files with 742 additions and 160 deletions

View File

@@ -13,6 +13,7 @@ using namespace Windows::Foundation::Collections;
using namespace Windows::Storage::Streams;
using namespace Windows::System;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
@@ -54,6 +55,7 @@ namespace GraphControl
Grapher::Grapher()
: m_solver{ IMathSolver::CreateMathSolver() }
, m_graph{ m_solver->CreateGrapher() }
, m_Moving{ false }
{
m_solver->ParsingOptions().SetFormatType(FormatType::MathML);
@@ -67,6 +69,10 @@ namespace GraphControl
this->ManipulationMode = ManipulationModes::TranslateX | ManipulationModes::TranslateY | ManipulationModes::TranslateInertia | ManipulationModes::Scale
| ManipulationModes::ScaleInertia;
auto cw = CoreWindow::GetForCurrentThread();
cw->KeyDown += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &Grapher::OnCoreKeyDown);
cw->KeyUp += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &Grapher::OnCoreKeyUp);
}
void Grapher::OnLoaded(Object ^ sender, RoutedEventArgs ^ args)
@@ -126,6 +132,7 @@ namespace GraphControl
auto swapChainPanel = dynamic_cast<SwapChainPanel ^>(GetTemplateChild(StringReference(s_templateKey_SwapChainPanel)));
if (swapChainPanel)
{
swapChainPanel->AllowFocusOnInteraction = true;
m_renderMain = ref new RenderMain(swapChainPanel);
}
@@ -535,12 +542,27 @@ namespace GraphControl
}
}
void Grapher::UpdateTracingChanged()
{
if (m_renderMain->Tracing || m_renderMain->ActiveTracing)
{
TracingChangedEvent(true);
TracingValueChangedEvent(m_renderMain->TraceValue);
}
else
{
TracingChangedEvent(false);
}
}
void Grapher::OnPointerMoved(PointerRoutedEventArgs ^ e)
{
if (m_renderMain)
{
PointerPoint ^ currPoint = e->GetCurrentPoint(/* relativeTo */ this);
m_renderMain->PointerLocation = currPoint->Position;
UpdateTracingChanged();
e->Handled = true;
}
@@ -551,6 +573,11 @@ namespace GraphControl
if (m_renderMain)
{
m_renderMain->DrawNearestPoint = false;
if (ActiveTracing == false)
{
// IF we are active tracing we never want to hide the popup..
TracingChangedEvent(false);
}
e->Handled = true;
}
}
@@ -699,3 +726,175 @@ namespace GraphControl
return outputStream;
}
}
void Grapher::OnCoreKeyUp(CoreWindow ^ sender, KeyEventArgs ^ e)
{
// We don't want to react to keyboard input unless the graph control has the focus.
// NOTE: you can't select the graph control from the mouse for focus but you can tab to it.
GraphControl::Grapher ^ gcHasFocus = dynamic_cast<GraphControl::Grapher ^>(FocusManager::GetFocusedElement());
if (gcHasFocus == nullptr || gcHasFocus != this)
{
// Not a graphingCalculator control so we don't want the input.
return;
}
switch (e->VirtualKey)
{
case VirtualKey::Left:
case VirtualKey::Right:
case VirtualKey::Down:
case VirtualKey::Up:
case VirtualKey::Shift:
{
HandleKey(false, e->VirtualKey);
}
break;
}
}
void Grapher::OnCoreKeyDown(CoreWindow ^ sender, KeyEventArgs ^ e)
{
// We don't want to react to any keys when we are not in the graph control
GraphControl::Grapher ^ gcHasFocus = dynamic_cast<GraphControl::Grapher ^>(FocusManager::GetFocusedElement());
if (gcHasFocus == nullptr || gcHasFocus != this)
{
// Not a graphingCalculator control so we don't want the input.
return;
}
switch (e->VirtualKey)
{
case VirtualKey::Left:
case VirtualKey::Right:
case VirtualKey::Down:
case VirtualKey::Up:
case VirtualKey::Shift:
{
HandleKey(true, e->VirtualKey);
}
break;
}
}
void Grapher::HandleKey(bool keyDown, VirtualKey key)
{
int pressedKeys = 0;
if (key == VirtualKey::Left)
{
m_KeysPressed[KeysPressedSlots::Left] = keyDown;
if (keyDown)
{
pressedKeys++;
}
}
if (key == VirtualKey::Right)
{
m_KeysPressed[KeysPressedSlots::Right] = keyDown;
if (keyDown)
{
pressedKeys++;
}
}
if (key == VirtualKey::Up)
{
m_KeysPressed[KeysPressedSlots::Up] = keyDown;
if (keyDown)
{
pressedKeys++;
}
}
if (key == VirtualKey::Down)
{
m_KeysPressed[KeysPressedSlots::Down] = keyDown;
if (keyDown)
{
pressedKeys++;
}
}
if (key == VirtualKey::Shift)
{
m_KeysPressed[KeysPressedSlots::Accelerator] = keyDown;
}
if (pressedKeys > 0 && !m_Moving)
{
m_Moving = true;
// Key(s) we care about, so ensure we are ticking our timer (and that we have one to tick)
if (m_TracingTrackingTimer == nullptr)
{
m_TracingTrackingTimer = ref new DispatcherTimer();
m_TracingTrackingTimer->Tick += ref new EventHandler<Object ^>(this, &Grapher::HandleTracingMovementTick);
TimeSpan ts;
ts.Duration = 100000; // .1 second
m_TracingTrackingTimer->Interval = ts;
auto i = m_TracingTrackingTimer->Interval;
}
m_TracingTrackingTimer->Start();
}
}
void Grapher::HandleTracingMovementTick(Object ^ sender, Object ^ e)
{
int delta = 5;
int liveKeys = 0;
if (m_KeysPressed[KeysPressedSlots::Accelerator])
{
delta = 1;
}
auto curPos = ActiveTraceCursorPosition;
if (m_KeysPressed[KeysPressedSlots::Left])
{
liveKeys++;
curPos.X -= delta;
if (curPos.X < 0)
{
curPos.X = 0;
}
}
if (m_KeysPressed[KeysPressedSlots::Right])
{
liveKeys++;
curPos.X += delta;
if (curPos.X > ActualWidth - delta)
{
curPos.X = (float)ActualWidth - delta; // TODO change this to deal with size of cursor
}
}
if (m_KeysPressed[KeysPressedSlots::Up])
{
liveKeys++;
curPos.Y -= delta;
if (curPos.Y < 0)
{
curPos.Y = 0;
}
}
if (m_KeysPressed[KeysPressedSlots::Down])
{
liveKeys++;
curPos.Y += delta;
if (curPos.Y > ActualHeight - delta)
{
curPos.Y = (float)ActualHeight - delta; // TODO change this to deal with size of cursor
}
}
if (liveKeys == 0)
{
m_Moving = false;
// Non of the keys we care about are being hit any longer so shut down our timer
m_TracingTrackingTimer->Stop();
}
else
{
ActiveTraceCursorPosition = curPos;
}
}

View File

@@ -9,15 +9,24 @@
namespace GraphControl
{
[Windows::UI::Xaml::Markup::ContentPropertyAttribute(Name = L"Equations")]
public ref class Grapher sealed : public Windows::UI::Xaml::Controls::Control
public
delegate void TracingChangedEventHandler(bool newValue);
public
delegate void TracingValueChangedEventHandler(Windows::Foundation::Point value);
[Windows::UI::Xaml::Markup::ContentPropertyAttribute(Name = L"Equations")] public ref class Grapher sealed : public Windows::UI::Xaml::Controls::Control
{
public:
event TracingValueChangedEventHandler ^ TracingValueChangedEvent;
event TracingChangedEventHandler ^ TracingChangedEvent;
public:
Grapher();
static void RegisterDependencyProperties();
#pragma region Windows::UI::Xaml::DataTemplate^ EquationTemplate DependencyProperty
#pragma region Windows::UI::Xaml::DataTemplate ^ EquationTemplate DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ EquationTemplateProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
@@ -37,9 +46,9 @@ namespace GraphControl
SetValue(s_equationTemplateProperty, value);
}
}
#pragma endregion
#pragma endregion
#pragma region Platform::Object^ EquationsSource DependencyProperty
#pragma region Platform::Object ^ EquationsSource DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ EquationsSourceProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
@@ -59,9 +68,9 @@ namespace GraphControl
SetValue(s_equationsSourceProperty, value);
}
}
#pragma endregion
#pragma endregion
#pragma region GraphControl::EquationCollection^ Equations DependencyProperty
#pragma region GraphControl::EquationCollection ^ Equations DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ EquationsProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
@@ -77,9 +86,9 @@ namespace GraphControl
return static_cast< GraphControl::EquationCollection^ >(GetValue(s_equationsProperty));
}
}
#pragma endregion
#pragma endregion
#pragma region Windows::Foundation::Collections::IObservableMap<Platform::String^, double>^ Variables DependencyProperty
#pragma region Windows::Foundation::Collections::IObservableMap < Platform::String ^, double> ^ Variables DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ VariablesProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
@@ -100,9 +109,9 @@ namespace GraphControl
SetValue(s_variablesProperty, value);
}
}
#pragma endregion
#pragma endregion
#pragma region Windows::UI::Xaml::DataTemplate^ ForceProportionalAxes DependencyProperty
#pragma region Windows::UI::Xaml::DataTemplate ^ ForceProportionalAxes DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ ForceProportionalAxesTemplateProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
@@ -122,52 +131,103 @@ namespace GraphControl
SetValue(s_forceProportionalAxesTemplateProperty, value);
}
}
#pragma endregion
#pragma endregion
event Windows::Foundation::EventHandler<Windows::Foundation::Collections::IMap<Platform::String^, double>^>^ VariablesUpdated;
// Pass active tracing turned on or off down to the renderer
property bool ActiveTracing
{
bool get()
{
return m_renderMain->ActiveTracing;
}
void set(bool value)
{
m_renderMain->ActiveTracing = value;
UpdateTracingChanged();
}
}
void SetVariable(Platform::String^ variableName, double newValue);
void ZoomFromCenter(double scale);
void ResetGrid();
property Windows::Foundation::Point TraceValue
{
Windows::Foundation::Point get()
{
return m_renderMain->TraceValue;
}
}
property Windows::Foundation::Point TraceLocation
{
Windows::Foundation::Point get()
{
return m_renderMain->TraceLocation;
}
}
property Windows::Foundation::Point ActiveTraceCursorPosition
{
Windows::Foundation::Point get()
{
return m_renderMain->ActiveTraceCursorPosition;
}
void set(Windows::Foundation::Point newValue)
{
if (m_renderMain->ActiveTraceCursorPosition != newValue)
{
m_renderMain->ActiveTraceCursorPosition = newValue;
UpdateTracingChanged();
}
}
}
event Windows::Foundation::EventHandler<Windows::Foundation::Collections::IMap<Platform::String ^, double> ^> ^ VariablesUpdated;
void SetVariable(Platform::String ^ variableName, double newValue);
protected:
#pragma region Control Overrides
#pragma region Control Overrides
void OnApplyTemplate() override;
void OnPointerEntered(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnPointerMoved(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnPointerExited(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnPointerWheelChanged(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnPointerPressed(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnPointerReleased(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnPointerCanceled(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) override;
void OnManipulationDelta(Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs^ e) override;
#pragma endregion
void OnPointerEntered(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnPointerMoved(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnPointerExited(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnPointerWheelChanged(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnPointerPressed(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnPointerReleased(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnPointerCanceled(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
void OnManipulationDelta(Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs ^ e) override;
#pragma endregion
private:
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ args);
void OnUnloaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ args);
void OnLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ args);
void OnUnloaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ args);
static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ args);
void OnDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject^ obj, Windows::UI::Xaml::DependencyProperty^ p);
static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyProperty ^ p);
void OnEquationTemplateChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ args);
void OnEquationTemplateChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnEquationsSourceChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ args);
void OnDataSourceChanged(GraphControl::InspectingDataSource^ sender, GraphControl::DataSourceChangedEventArgs args);
void OnEquationsSourceChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnDataSourceChanged(GraphControl::InspectingDataSource ^ sender, GraphControl::DataSourceChangedEventArgs args);
void OnEquationsChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ args);
void OnEquationsVectorChanged(Windows::Foundation::Collections::IObservableVector<GraphControl::Equation ^> ^sender, Windows::Foundation::Collections::IVectorChangedEventArgs^ event);
void OnEquationsChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnEquationsVectorChanged(
Windows::Foundation::Collections::IObservableVector<GraphControl::Equation ^> ^ sender,
Windows::Foundation::Collections::IVectorChangedEventArgs ^ event);
void OnEquationChanged();
void OnEquationStyleChanged();
void UpdateGraph();
void UpdateGraphOptions(Graphing::IGraphingOptions& options, const std::vector<Equation^>& validEqs);
std::vector<Equation^> GetValidEquations();
void UpdateGraphOptions(Graphing::IGraphingOptions& options, const std::vector<Equation ^>& validEqs);
std::vector<Equation ^> GetValidEquations();
void SetGraphArgs();
void UpdateVariables();
void OnForceProportionalAxesChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ args);
void OnForceProportionalAxesChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnBackgroundColorChanged(const Windows::UI::Color& color);
@@ -177,29 +237,52 @@ namespace GraphControl
void ScaleRange(double centerX, double centerY, double scale);
void OnCoreKeyDown(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ e);
void OnCoreKeyUp(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ e);
void UpdateTracingChanged();
void HandleTracingMovementTick(Object ^ sender, Object ^ e);
void HandleKey(bool keyDown, Windows::System::VirtualKey key);
private:
DX::RenderMain^ m_renderMain = nullptr;
DX::RenderMain ^ m_renderMain = nullptr;
static Windows::UI::Xaml::DependencyProperty^ s_equationTemplateProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_equationTemplateProperty;
static Windows::UI::Xaml::DependencyProperty^ s_equationsSourceProperty;
InspectingDataSource^ m_dataSource;
static Windows::UI::Xaml::DependencyProperty ^ s_equationsSourceProperty;
InspectingDataSource ^ m_dataSource;
Windows::Foundation::EventRegistrationToken m_tokenDataSourceChanged;
static Windows::UI::Xaml::DependencyProperty^ s_equationsProperty;
static Windows::UI::Xaml::DependencyProperty^ s_variablesProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_equationsProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_variablesProperty;
Windows::Foundation::EventRegistrationToken m_tokenEquationsChanged;
Windows::Foundation::EventRegistrationToken m_tokenEquationStyleChanged;
Windows::Foundation::EventRegistrationToken m_tokenEquationChanged;
static Windows::UI::Xaml::DependencyProperty^ s_forceProportionalAxesTemplateProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_forceProportionalAxesTemplateProperty;
Windows::Foundation::EventRegistrationToken m_tokenBackgroundColorChanged;
const std::unique_ptr<Graphing::IMathSolver> m_solver;
const std::shared_ptr<Graphing::IGraph> m_graph;
public:
Windows::Storage::Streams::RandomAccessStreamReference^ GetGraphBitmapStream();
bool m_tracingTracking;
enum KeysPressedSlots
{
Left,
Right,
Down,
Up,
Accelerator
};
bool m_KeysPressed[5];
bool m_Moving;
Windows::UI::Xaml::DispatcherTimer ^ m_TracingTrackingTimer;
public:
Windows::Storage::Streams::RandomAccessStreamReference ^ GetGraphBitmapStream();
};
}

View File

@@ -0,0 +1,78 @@
#include "pch.h"
#include "ActiveTracingPointRenderer.h"
#include "DirectXHelper.h"
using namespace D2D1;
using namespace GraphControl::DX;
using namespace std;
using namespace Windows::Foundation;
namespace
{
const ColorF c_DefaultPointColor = ColorF::Red;
constexpr float c_ActiveTracingPointRadius = 2;
}
ActiveTracingPointRenderer::ActiveTracingPointRenderer(DeviceResources* deviceResources)
: m_deviceResources{ deviceResources }
, m_color{ c_DefaultPointColor }
{
m_RoundedRect.rect.bottom = 0;
m_RoundedRect.rect.left = 0;
m_RoundedRect.rect.right = 10;
m_RoundedRect.rect.top = 10;
m_width = (int)(m_RoundedRect.rect.right - m_RoundedRect.rect.left);
m_height = (int)(m_RoundedRect.rect.top - m_RoundedRect.rect.bottom);
m_RoundedRect.radiusX = c_ActiveTracingPointRadius;
m_RoundedRect.radiusY = c_ActiveTracingPointRadius;
CreateDeviceDependentResources();
}
void ActiveTracingPointRenderer::CreateDeviceDependentResources()
{
CreateBrush();
}
void ActiveTracingPointRenderer::ReleaseDeviceDependentResources()
{
m_brush.Reset();
}
void ActiveTracingPointRenderer::Render(const Point& location)
{
// We want to center this around the location
if (ID2D1DeviceContext* context = m_deviceResources->GetD2DDeviceContext())
{
m_RoundedRect.rect.bottom = location.Y - m_height / 2;
m_RoundedRect.rect.left = location.X - m_width / 2;
m_RoundedRect.rect.top = m_RoundedRect.rect.bottom + m_height;
m_RoundedRect.rect.right = m_RoundedRect.rect.left + m_width;
context->BeginDraw();
context->FillRoundedRectangle(m_RoundedRect, m_brush.Get());
// Ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
// is lost. It will be handled during the next call to Present.
HRESULT hr = context->EndDraw();
if (hr != D2DERR_RECREATE_TARGET)
{
ThrowIfFailed(hr);
}
}
}
void ActiveTracingPointRenderer::SetColor(const ColorF& color)
{
m_color = color;
CreateBrush();
}
void ActiveTracingPointRenderer::CreateBrush()
{
m_brush.Reset();
ThrowIfFailed(
m_deviceResources->GetD2DDeviceContext()->CreateSolidColorBrush(m_color, &m_brush)
);
}

View File

@@ -0,0 +1,32 @@
#pragma once
namespace GraphControl::DX
{
class DeviceResources;
class ActiveTracingPointRenderer
{
public:
ActiveTracingPointRenderer(DeviceResources* deviceResources);
void CreateDeviceDependentResources();
void ReleaseDeviceDependentResources();
void Render(const Windows::Foundation::Point& location);
void SetColor(const D2D1::ColorF& color);
private:
void CreateBrush();
private:
DeviceResources* const m_deviceResources;
D2D1::ColorF m_color;
D2D1_ROUNDED_RECT m_RoundedRect;
int m_width;
int m_height;
// Resources related to rendering.
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> m_brush;
};
}

View File

@@ -26,16 +26,24 @@ namespace
namespace GraphControl::DX
{
RenderMain::RenderMain(SwapChainPanel^ panel) :
m_deviceResources{ panel },
m_nearestPointRenderer{ &m_deviceResources },
m_backgroundColor{ {} },
m_swapChainPanel{ panel }
RenderMain::RenderMain(SwapChainPanel ^ panel)
: m_deviceResources{ panel }
, m_nearestPointRenderer{ &m_deviceResources }
, m_backgroundColor{ {} }
, m_swapChainPanel{ panel }
, m_TraceValue(Point(0, 0))
, m_TraceLocation(Point(0,0))
, m_Tracing(false)
, m_ActiveTracingPointRenderer{ &m_deviceResources }
{
// Register to be notified if the Device is lost or recreated
m_deviceResources.RegisterDeviceNotify(this);
RegisterEventHandlers();
m_drawActiveTracing = false;
m_activeTracingPointerLocation.X = 50;
m_activeTracingPointerLocation.Y = 50;
}
RenderMain::~RenderMain()
@@ -43,7 +51,7 @@ namespace GraphControl::DX
UnregisterEventHandlers();
}
void RenderMain::Graph::set(shared_ptr< IGraph > graph)
void RenderMain::Graph::set(shared_ptr<IGraph> graph)
{
m_graph = move(graph);
@@ -54,9 +62,7 @@ namespace GraphControl::DX
float dpi = m_deviceResources.GetDpi();
renderer->SetDpi(dpi, dpi);
renderer->SetGraphSize(
static_cast<unsigned int>(m_swapChainPanel->ActualWidth),
static_cast<unsigned int>(m_swapChainPanel->ActualHeight));
renderer->SetGraphSize(static_cast<unsigned int>(m_swapChainPanel->ActualWidth), static_cast<unsigned int>(m_swapChainPanel->ActualHeight));
}
}
@@ -65,9 +71,9 @@ namespace GraphControl::DX
void RenderMain::BackgroundColor::set(Windows::UI::Color backgroundColor)
{
m_backgroundColor[s_RedChannelIndex] = static_cast<float>(backgroundColor.R) / s_MaxChannelValue;
m_backgroundColor[s_RedChannelIndex] = static_cast<float>(backgroundColor.R) / s_MaxChannelValue;
m_backgroundColor[s_GreenChannelIndex] = static_cast<float>(backgroundColor.G) / s_MaxChannelValue;
m_backgroundColor[s_BlueChannelIndex] = static_cast<float>(backgroundColor.B) / s_MaxChannelValue;
m_backgroundColor[s_BlueChannelIndex] = static_cast<float>(backgroundColor.B) / s_MaxChannelValue;
m_backgroundColor[s_AlphaChannelIndex] = static_cast<float>(backgroundColor.A) / s_MaxChannelValue;
RunRenderPass();
@@ -78,6 +84,10 @@ namespace GraphControl::DX
if (m_drawNearestPoint != value)
{
m_drawNearestPoint = value;
if (!m_drawNearestPoint)
{
m_Tracing = false;
}
RunRenderPass();
}
}
@@ -91,6 +101,20 @@ namespace GraphControl::DX
}
}
void RenderMain::ActiveTracing::set(bool value)
{
if (m_drawActiveTracing != value)
{
m_drawActiveTracing = value;
RunRenderPass();
}
}
bool RenderMain::ActiveTracing::get()
{
return m_drawActiveTracing;
}
// Updates application state when the window size changes (e.g. device orientation change)
void RenderMain::CreateWindowSizeDependentResources()
{
@@ -113,8 +137,8 @@ namespace GraphControl::DX
bool successful = true;
// Must call BeginDraw before any draw commands.
ID2D1Factory3 *pFactory = m_deviceResources.GetD2DFactory();
ID2D1DeviceContext *pRenderTarget = m_deviceResources.GetD2DDeviceContext();
ID2D1Factory3* pFactory = m_deviceResources.GetD2DFactory();
ID2D1DeviceContext* pRenderTarget = m_deviceResources.GetD2DDeviceContext();
auto context = m_deviceResources.GetD3DDeviceContext();
@@ -138,20 +162,43 @@ namespace GraphControl::DX
DX::ThrowIfFailed(endDraw);
}
if (successful && m_drawNearestPoint)
if (successful)
{
int formulaId;
Point nearestPointLocation;
pair<float, float> nearestPointValue;
renderer->GetClosePointData(
m_pointerLocation.X, m_pointerLocation.Y,
formulaId,
nearestPointLocation.X, nearestPointLocation.Y,
nearestPointValue.first, nearestPointValue.second);
if (!isnan(nearestPointLocation.X) && !isnan(nearestPointLocation.Y))
if (m_drawNearestPoint || m_drawActiveTracing)
{
m_nearestPointRenderer.Render(nearestPointLocation);
Point trackPoint = m_pointerLocation;
if (m_drawActiveTracing)
{
// Active tracing takes over for draw nearest point input from the mouse pointer.
trackPoint = m_activeTracingPointerLocation;
m_ActiveTracingPointRenderer.Render(m_activeTracingPointerLocation);
}
int formulaId;
Point nearestPointLocation;
pair<float, float> nearestPointValue;
renderer->GetClosePointData(
trackPoint.X,
trackPoint.Y,
formulaId,
nearestPointLocation.X,
nearestPointLocation.Y,
nearestPointValue.first,
nearestPointValue.second);
if (!isnan(nearestPointLocation.X) && !isnan(nearestPointLocation.Y))
{
m_nearestPointRenderer.Render(nearestPointLocation);
m_Tracing = true;
m_TraceLocation = Point(nearestPointLocation.X, nearestPointLocation.Y);
m_TraceValue = Point(nearestPointValue.first, nearestPointValue.second);
}
else
{
m_Tracing = false;
}
}
}
}
@@ -160,7 +207,7 @@ namespace GraphControl::DX
return successful;
}
void RenderMain::OnLoaded(Object^ sender, RoutedEventArgs^ e)
void RenderMain::OnLoaded(Object ^ sender, RoutedEventArgs ^ e)
{
RunRenderPass();
}
@@ -173,39 +220,30 @@ namespace GraphControl::DX
m_coreWindow = Agile<CoreWindow>(Window::Current->CoreWindow);
if (m_coreWindow != nullptr)
{
m_tokenVisibilityChanged =
m_coreWindow->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &RenderMain::OnVisibilityChanged);
m_tokenVisibilityChanged = m_coreWindow->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow ^, VisibilityChangedEventArgs ^>(this, &RenderMain::OnVisibilityChanged);
}
m_displayInformation = DisplayInformation::GetForCurrentView();
if (m_displayInformation != nullptr)
{
m_tokenDpiChanged =
m_displayInformation->DpiChanged +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &RenderMain::OnDpiChanged);
m_tokenDpiChanged = m_displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &RenderMain::OnDpiChanged);
m_tokenOrientationChanged =
m_displayInformation->OrientationChanged +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &RenderMain::OnOrientationChanged);
m_tokenOrientationChanged = m_displayInformation->OrientationChanged +=
ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &RenderMain::OnOrientationChanged);
}
m_tokenDisplayContentsInvalidated =
DisplayInformation::DisplayContentsInvalidated +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &RenderMain::OnDisplayContentsInvalidated);
m_tokenDisplayContentsInvalidated = DisplayInformation::DisplayContentsInvalidated +=
ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &RenderMain::OnDisplayContentsInvalidated);
if (m_swapChainPanel != nullptr)
{
m_tokenLoaded =
m_swapChainPanel->Loaded += ref new RoutedEventHandler(this, &RenderMain::OnLoaded);
m_tokenLoaded = m_swapChainPanel->Loaded += ref new RoutedEventHandler(this, &RenderMain::OnLoaded);
m_tokenCompositionScaleChanged =
m_swapChainPanel->CompositionScaleChanged +=
ref new TypedEventHandler< SwapChainPanel^, Object^ >(this, &RenderMain::OnCompositionScaleChanged);
m_tokenCompositionScaleChanged = m_swapChainPanel->CompositionScaleChanged +=
ref new TypedEventHandler<SwapChainPanel ^, Object ^>(this, &RenderMain::OnCompositionScaleChanged);
m_tokenSizeChanged =
m_swapChainPanel->SizeChanged +=
ref new SizeChangedEventHandler(this, &RenderMain::OnSizeChanged);
m_tokenSizeChanged = m_swapChainPanel->SizeChanged += ref new SizeChangedEventHandler(this, &RenderMain::OnSizeChanged);
}
}
@@ -262,7 +300,7 @@ namespace GraphControl::DX
}
}
void RenderMain::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
void RenderMain::OnVisibilityChanged(CoreWindow ^ sender, VisibilityChangedEventArgs ^ args)
{
if (args->Visible)
{
@@ -270,7 +308,7 @@ namespace GraphControl::DX
}
}
void RenderMain::OnDpiChanged(DisplayInformation^ sender, Object^ args)
void RenderMain::OnDpiChanged(DisplayInformation ^ sender, Object ^ args)
{
// Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app
// if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources,
@@ -290,24 +328,24 @@ namespace GraphControl::DX
CreateWindowSizeDependentResources();
}
void RenderMain::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
void RenderMain::OnOrientationChanged(DisplayInformation ^ sender, Object ^ args)
{
m_deviceResources.SetCurrentOrientation(sender->CurrentOrientation);
CreateWindowSizeDependentResources();
}
void RenderMain::OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
void RenderMain::OnDisplayContentsInvalidated(DisplayInformation ^ sender, Object ^ args)
{
m_deviceResources.ValidateDevice();
}
void RenderMain::OnCompositionScaleChanged(SwapChainPanel^ sender, Object^ args)
void RenderMain::OnCompositionScaleChanged(SwapChainPanel ^ sender, Object ^ args)
{
m_deviceResources.SetCompositionScale(sender->CompositionScaleX, sender->CompositionScaleY);
CreateWindowSizeDependentResources();
}
void RenderMain::OnSizeChanged(Object^ sender, SizeChangedEventArgs^ e)
void RenderMain::OnSizeChanged(Object ^ sender, SizeChangedEventArgs ^ e)
{
m_deviceResources.SetLogicalSize(e->NewSize);
@@ -316,9 +354,7 @@ namespace GraphControl::DX
if (auto renderer = m_graph->GetRenderer())
{
const auto& newSize = e->NewSize;
renderer->SetGraphSize(
static_cast<unsigned int>(newSize.Width),
static_cast<unsigned int>(newSize.Height));
renderer->SetGraphSize(static_cast<unsigned int>(newSize.Width), static_cast<unsigned int>(newSize.Height));
}
}

View File

@@ -4,6 +4,7 @@
#include "DeviceResources.h"
#include "NearestPointRenderer.h"
#include "ActiveTracingPointRenderer.h"
#include "IGraph.h"
// Renders Direct2D and 3D content on the screen.
@@ -18,12 +19,11 @@ namespace GraphControl::DX
virtual void OnDeviceLost();
virtual void OnDeviceRestored();
internal:
RenderMain(Windows::UI::Xaml::Controls::SwapChainPanel^ panel);
internal : RenderMain(Windows::UI::Xaml::Controls::SwapChainPanel ^ panel);
property std::shared_ptr< Graphing::IGraph > Graph
property std::shared_ptr<Graphing::IGraph> Graph
{
void set(std::shared_ptr< Graphing::IGraph > graph);
void set(std::shared_ptr<Graphing::IGraph> graph);
}
property Windows::UI::Color BackgroundColor
@@ -40,48 +40,103 @@ namespace GraphControl::DX
{
void set(Windows::Foundation::Point location);
}
void CreateWindowSizeDependentResources();
void RunRenderPass();
// Indicates if we are in active tracing mode (the tracing box is being used and controlled through keyboard input)
property bool ActiveTracing
{
bool get();
void set(bool value);
}
property Windows::Foundation::Point ActiveTraceCursorPosition
{
Windows::Foundation::Point get()
{
return m_activeTracingPointerLocation;
}
void set(Windows::Foundation::Point newValue)
{
if (m_activeTracingPointerLocation != newValue)
{
m_activeTracingPointerLocation = newValue;
m_ActiveTracingPointRenderer.Render(m_activeTracingPointerLocation);
RunRenderPass();
}
}
}
property Windows::Foundation::Point TraceValue
{
Windows::Foundation::Point get()
{
return m_TraceValue;
}
}
property Windows::Foundation::Point TraceLocation
{
Windows::Foundation::Point get()
{
return m_TraceLocation;
}
}
// Any time we should be showing the tracing popup (either active or passive tracing)
property bool Tracing
{
bool get()
{
return m_Tracing;
}
}
private:
bool Render();
// Loaded/Unloaded
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
// Dependent event registration
void RegisterEventHandlers();
void UnregisterEventHandlers();
// Window event handlers.
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
void OnVisibilityChanged(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::VisibilityChangedEventArgs ^ args);
// DisplayInformation event handlers.
void OnDpiChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
void OnDisplayContentsInvalidated(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
void OnDpiChanged(Windows::Graphics::Display::DisplayInformation ^ sender, Platform::Object ^ args);
void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation ^ sender, Platform::Object ^ args);
void OnDisplayContentsInvalidated(Windows::Graphics::Display::DisplayInformation ^ sender, Platform::Object ^ args);
// Other event handlers.
void OnCompositionScaleChanged(Windows::UI::Xaml::Controls::SwapChainPanel^ sender, Object^ args);
void OnSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
void OnCompositionScaleChanged(Windows::UI::Xaml::Controls::SwapChainPanel ^ sender, Object ^ args);
void OnSizeChanged(Platform::Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
private:
DX::DeviceResources m_deviceResources;
NearestPointRenderer m_nearestPointRenderer;
ActiveTracingPointRenderer m_ActiveTracingPointRenderer;
// Cached Graph object with Renderer property.
std::shared_ptr< Graphing::IGraph > m_graph = nullptr;
std::shared_ptr<Graphing::IGraph> m_graph = nullptr;
// Track current input pointer position.
bool m_drawNearestPoint = false;
Windows::Foundation::Point m_pointerLocation;
// Track current active tracing pointer position.
bool m_drawActiveTracing = false;
Windows::Foundation::Point m_activeTracingPointerLocation;
float m_backgroundColor[4];
// The SwapChainPanel^ surface.
Windows::UI::Xaml::Controls::SwapChainPanel^ m_swapChainPanel = nullptr;
// The SwapChainPanel^ surface.
Windows::UI::Xaml::Controls::SwapChainPanel ^ m_swapChainPanel = nullptr;
Windows::Foundation::EventRegistrationToken m_tokenLoaded;
Windows::Foundation::EventRegistrationToken m_tokenCompositionScaleChanged;
Windows::Foundation::EventRegistrationToken m_tokenSizeChanged;
@@ -90,13 +145,22 @@ namespace GraphControl::DX
Platform::Agile<Windows::UI::Core::CoreWindow> m_coreWindow = nullptr;
Windows::Foundation::EventRegistrationToken m_tokenVisibilityChanged;
Windows::Graphics::Display::DisplayInformation^ m_displayInformation = nullptr;
Windows::Graphics::Display::DisplayInformation ^ m_displayInformation = nullptr;
Windows::Foundation::EventRegistrationToken m_tokenDpiChanged;
Windows::Foundation::EventRegistrationToken m_tokenOrientationChanged;
Windows::Foundation::EventRegistrationToken m_tokenDisplayContentsInvalidated;
// Track our independent input on a background worker thread.
Windows::Foundation::IAsyncAction^ m_inputLoopWorker = nullptr;
Windows::UI::Core::CoreIndependentInputSource^ m_coreInput = nullptr;
Windows::Foundation::IAsyncAction ^ m_inputLoopWorker = nullptr;
Windows::UI::Core::CoreIndependentInputSource ^ m_coreInput = nullptr;
// What is the current trace value
Windows::Foundation::Point m_TraceValue;
// And where is it located on screen
Windows::Foundation::Point m_TraceLocation;
// Are we currently showing the tracing value
bool m_Tracing;
};
}

View File

@@ -308,6 +308,7 @@
<ClInclude Include="Control\EquationCollection.h" />
<ClInclude Include="Control\Grapher.h" />
<ClInclude Include="Control\InspectingDataSource.h" />
<ClInclude Include="DirectX\ActiveTracingPointRenderer.h" />
<ClInclude Include="DirectX\DeviceResources.h" />
<ClInclude Include="DirectX\DirectXHelper.h" />
<ClInclude Include="DirectX\NearestPointRenderer.h" />
@@ -319,6 +320,7 @@
<ClCompile Include="Control\Equation.cpp" />
<ClCompile Include="Control\Grapher.cpp" />
<ClCompile Include="Control\InspectingDataSource.cpp" />
<ClCompile Include="DirectX\ActiveTracingPointRenderer.cpp" />
<ClCompile Include="DirectX\DeviceResources.cpp" />
<ClCompile Include="DirectX\NearestPointRenderer.cpp" />
<ClCompile Include="DirectX\RenderMain.cpp" />

View File

@@ -31,6 +31,9 @@
<ClCompile Include="DirectX\NearestPointRenderer.cpp">
<Filter>DirectX</Filter>
</ClCompile>
<ClCompile Include="DirectX\ActiveTracingPointRenderer.cpp">
<Filter>DirectX</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -59,6 +62,9 @@
<ClInclude Include="DirectX\NearestPointRenderer.h">
<Filter>DirectX</Filter>
</ClInclude>
<ClInclude Include="DirectX\ActiveTracingPointRenderer.h">
<Filter>DirectX</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Page Include="Themes\generic.xaml">