Add Graph Settings (#879)

This commit is contained in:
Rudy Huyn 2020-01-03 15:06:14 -08:00 committed by GitHub
parent 234ac8deb3
commit 8357f5d5c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 1882 additions and 195 deletions

View file

@ -190,7 +190,7 @@ void ApplicationViewModel::OnCopyCommand(Object ^ parameter)
{
DateCalcViewModel->OnCopyCommand(parameter);
}
else
else if (NavCategory::IsCalculatorViewMode(m_mode))
{
CalculatorViewModel->OnCopyCommand(parameter);
}

View file

@ -332,6 +332,7 @@
<ClInclude Include="GraphingCalculator\EquationViewModel.h" />
<ClInclude Include="GraphingCalculator\GraphingCalculatorViewModel.h" />
<ClInclude Include="GraphingCalculator\VariableViewModel.h" />
<ClInclude Include="GraphingCalculator\GraphingSettingsViewModel.h" />
<ClInclude Include="HistoryItemViewModel.h" />
<ClInclude Include="HistoryViewModel.h" />
<ClInclude Include="MemoryItemViewModel.h" />
@ -366,6 +367,7 @@
<ClCompile Include="DateCalculatorViewModel.cpp" />
<ClCompile Include="GraphingCalculator\EquationViewModel.cpp" />
<ClCompile Include="GraphingCalculator\GraphingCalculatorViewModel.cpp" />
<ClCompile Include="GraphingCalculator\GraphingSettingsViewModel.cpp" />
<ClCompile Include="HistoryItemViewModel.cpp" />
<ClCompile Include="HistoryViewModel.cpp" />
<ClCompile Include="MemoryItemViewModel.cpp" />
@ -421,4 +423,4 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.UI.Xaml.2.2.190830001\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.UI.Xaml.2.2.190830001\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
</Project>
</Project>

View file

@ -92,6 +92,9 @@
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="GraphingCalculator\GraphingSettingsViewModel.cpp">
<Filter>GraphingCalculator</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@ -220,6 +223,9 @@
<ClInclude Include="GraphingCalculator\VariableViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
<ClInclude Include="GraphingCalculator\GraphingSettingsViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="DataLoaders\DefaultFromToCurrency.json">

View file

@ -0,0 +1,164 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "GraphingSettingsViewModel.h"
#include <CalcManager\NumberFormattingUtils.h>
using namespace CalculatorApp::ViewModel;
using namespace CalcManager::NumberFormattingUtils;
using namespace GraphControl;
using namespace std;
using namespace Platform;
GraphingSettingsViewModel::GraphingSettingsViewModel()
: m_XMinValue(0)
, m_XMaxValue(0)
, m_YMinValue(0)
, m_YMaxValue(0)
, m_XMinError(false)
, m_XMaxError(false)
, m_YMinError(false)
, m_YMaxError(false)
, m_dontUpdateDisplayRange(false)
, m_XIsMinLastChanged(true)
, m_YIsMinLastChanged(true)
{
}
void GraphingSettingsViewModel::SetGrapher(Grapher ^ grapher)
{
if (grapher != nullptr)
{
if (grapher->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Invalid)
{
grapher->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Radians;
}
}
Graph = grapher;
InitRanges();
RaisePropertyChanged(L"TrigUnit");
}
void GraphingSettingsViewModel::InitRanges()
{
double xMin = 0, xMax = 0, yMin = 0, yMax = 0;
if (m_Graph != nullptr)
{
m_Graph->GetDisplayRanges(&xMin, &xMax, &yMin, &yMax);
}
m_dontUpdateDisplayRange = true;
m_XMinValue = xMin;
m_XMaxValue = xMax;
m_YMinValue = yMin;
m_YMaxValue = yMax;
auto valueStr = to_wstring(m_XMinValue);
TrimTrailingZeros(valueStr);
m_XMin = ref new String(valueStr.c_str());
valueStr = to_wstring(m_XMaxValue);
TrimTrailingZeros(valueStr);
m_XMax = ref new String(valueStr.c_str());
valueStr = to_wstring(m_YMinValue);
TrimTrailingZeros(valueStr);
m_YMin = ref new String(valueStr.c_str());
valueStr = to_wstring(m_YMaxValue);
TrimTrailingZeros(valueStr);
m_YMax = ref new String(valueStr.c_str());
m_dontUpdateDisplayRange = false;
}
void GraphingSettingsViewModel::RefreshPosition()
{
if (HasError())
{
InitRanges();
}
else
{
if (m_Graph != nullptr)
{
m_Graph->SetDisplayRanges(m_XMinValue, m_XMaxValue, m_YMinValue, m_YMaxValue);
}
}
}
void GraphingSettingsViewModel::UpdateDisplayRange(bool XValuesModified)
{
if (m_Graph == nullptr || m_dontUpdateDisplayRange || HasError())
{
return;
}
if (m_Graph->ForceProportionalAxes)
{
// If ForceProportionalAxes is set, the graph will try to automatically adjust ranges to remain proportional.
// but without a logic to choose which values can be modified or not.
// To solve this problem, we calculate the new ranges here, taking care to not modify the current axis and
// modifying only the least recently updated value of the other axis.
if (XValuesModified)
{
if (m_YIsMinLastChanged)
{
auto yMaxValue = m_YMinValue + (m_XMaxValue - m_XMinValue) * m_Graph->ActualHeight / m_Graph->ActualWidth;
if (m_YMaxValue != yMaxValue)
{
m_YMaxValue = yMaxValue;
auto valueStr = to_wstring(m_YMaxValue);
TrimTrailingZeros(valueStr);
m_YMax = ref new String(valueStr.c_str());
RaisePropertyChanged("YMax");
}
}
else
{
auto yMinValue = m_YMaxValue - (m_XMaxValue - m_XMinValue) * m_Graph->ActualHeight / m_Graph->ActualWidth;
if (m_YMinValue != yMinValue)
{
m_YMinValue = yMinValue;
auto valueStr = to_wstring(m_YMinValue);
TrimTrailingZeros(valueStr);
m_YMin = ref new String(valueStr.c_str());
RaisePropertyChanged("YMin");
}
}
}
else
{
if (m_XIsMinLastChanged)
{
auto xMaxValue = m_XMinValue + (m_YMaxValue - m_YMinValue) * m_Graph->ActualWidth / m_Graph->ActualHeight;
if (m_XMaxValue != xMaxValue)
{
m_XMaxValue = xMaxValue;
auto valueStr = to_wstring(m_XMaxValue);
TrimTrailingZeros(valueStr);
m_XMax = ref new String(valueStr.c_str());
RaisePropertyChanged("XMax");
}
}
else
{
auto xMinValue = m_XMaxValue - (m_YMaxValue - m_YMinValue) * m_Graph->ActualWidth / m_Graph->ActualHeight;
if (m_XMinValue != xMinValue)
{
m_XMinValue = xMinValue;
auto valueStr = to_wstring(m_XMinValue);
TrimTrailingZeros(valueStr);
m_XMin = ref new String(valueStr.c_str());
RaisePropertyChanged("XMin");
}
}
}
}
m_Graph->SetDisplayRanges(m_XMinValue, m_XMaxValue, m_YMinValue, m_YMaxValue);
}
bool GraphingSettingsViewModel::HasError()
{
return m_XMinError || m_YMinError || m_XMaxError || m_YMaxError || XError || YError;
}

View file

@ -0,0 +1,297 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "../Common/Utils.h"
namespace CalculatorApp::ViewModel
{
#pragma once
[Windows::UI::Xaml::Data::Bindable] public ref class GraphingSettingsViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(bool, YMinError);
OBSERVABLE_PROPERTY_R(bool, XMinError);
OBSERVABLE_PROPERTY_R(bool, XMaxError);
OBSERVABLE_PROPERTY_R(bool, YMaxError);
OBSERVABLE_PROPERTY_R(GraphControl::Grapher ^, Graph);
GraphingSettingsViewModel();
property bool XError
{
bool get()
{
return !m_XMinError && !m_XMaxError && m_XMinValue >= m_XMaxValue;
}
}
property bool YError
{
bool get()
{
return !m_YMinError && !m_YMaxError && m_YMinValue >= m_YMaxValue;
}
}
property Platform::String ^ XMin
{
Platform::String ^ get()
{
return m_XMin;
}
void set(Platform::String ^ value)
{
if (m_XMin == value)
{
return;
}
m_XMin = value;
m_XIsMinLastChanged = true;
if (m_Graph != nullptr)
{
try
{
size_t sz;
auto number = std::stod(value->Data(), &sz);
if (value->Length() == sz)
{
m_Graph->XAxisMin = m_XMinValue = number;
XMinError = false;
}
else
{
XMinError = true;
}
}
catch (...)
{
XMinError = true;
}
}
RaisePropertyChanged("XError");
RaisePropertyChanged("XMin");
UpdateDisplayRange(true);
}
}
property Platform::String ^ XMax
{
Platform::String ^ get()
{
return m_XMax;
}
void set(Platform::String ^ value)
{
if (m_XMax == value)
{
return;
}
m_XMax = value;
m_XIsMinLastChanged = false;
if (m_Graph != nullptr)
{
try
{
size_t sz;
auto number = std::stod(value->Data(), &sz);
if (value->Length() == sz)
{
m_Graph->XAxisMax = m_XMaxValue = number;
XMaxError = false;
}
else
{
XMaxError = true;
}
}
catch (...)
{
XMaxError = true;
}
}
RaisePropertyChanged("XError");
RaisePropertyChanged("XMax");
UpdateDisplayRange(true);
}
}
property Platform::String ^ YMin
{
Platform::String ^ get()
{
return m_YMin;
}
void set(Platform::String ^ value)
{
if (m_YMin == value)
{
return;
}
m_YMin = value;
m_YIsMinLastChanged = true;
if (m_Graph != nullptr)
{
try
{
size_t sz;
auto number = std::stod(value->Data(), &sz);
if (value->Length() == sz)
{
m_Graph->YAxisMin = m_YMinValue = number;
YMinError = false;
}
else
{
YMinError = true;
}
}
catch (...)
{
YMinError = true;
}
}
RaisePropertyChanged("YError");
RaisePropertyChanged("YMin");
UpdateDisplayRange(false);
}
}
property Platform::String ^ YMax
{
Platform::String ^ get()
{
return m_YMax;
}
void set(Platform::String ^ value)
{
if (m_YMax == value)
{
return;
}
m_YMax = value;
m_YIsMinLastChanged = false;
if (m_Graph != nullptr)
{
try
{
size_t sz;
auto number = std::stod(value->Data(), &sz);
if (value->Length() == sz)
{
m_Graph->YAxisMax = m_YMaxValue = number;
YMaxError = false;
}
else
{
YMaxError = true;
}
}
catch (...)
{
YMaxError = true;
}
}
RaisePropertyChanged("YError");
RaisePropertyChanged("YMax");
UpdateDisplayRange(false);
}
}
property int TrigUnit
{
int get()
{
return m_Graph == nullptr ? (int)Graphing::EvalTrigUnitMode::Invalid : m_Graph->TrigUnitMode;
}
void set(int value)
{
if (m_Graph == nullptr)
{
return;
}
m_Graph->TrigUnitMode = value;
RaisePropertyChanged(L"TrigUnit");
}
}
property bool TrigModeRadians
{
bool get()
{
return m_Graph != nullptr && m_Graph->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Radians;
}
void set(bool value)
{
if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Radians)
{
m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Radians;
RaisePropertyChanged(L"TrigModeRadians");
RaisePropertyChanged(L"TrigModeDegrees");
RaisePropertyChanged(L"TrigModeGradians");
RefreshPosition();
}
}
}
property bool TrigModeDegrees
{
bool get()
{
return m_Graph != nullptr && m_Graph->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Degrees;
}
void set(bool value)
{
if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Degrees)
{
m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Degrees;
RaisePropertyChanged(L"TrigModeDegrees");
RaisePropertyChanged(L"TrigModeRadians");
RaisePropertyChanged(L"TrigModeGradians");
RefreshPosition();
}
}
}
property bool TrigModeGradians
{
bool get()
{
return m_Graph != nullptr && m_Graph->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Grads;
}
void set(bool value)
{
if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Grads)
{
m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Grads;
RaisePropertyChanged(L"TrigModeGradians");
RaisePropertyChanged(L"TrigModeDegrees");
RaisePropertyChanged(L"TrigModeRadians");
RefreshPosition();
}
}
}
public:
void UpdateDisplayRange(bool XValuesModified);
void RefreshPosition();
public:
void SetGrapher(GraphControl::Grapher ^ grapher);
void InitRanges();
bool HasError();
private:
Platform::String ^ m_XMin;
Platform::String ^ m_XMax;
Platform::String ^ m_YMin;
Platform::String ^ m_YMax;
double m_XMinValue;
double m_XMaxValue;
double m_YMinValue;
double m_YMaxValue;
bool m_dontUpdateDisplayRange;
bool m_XIsMinLastChanged;
bool m_YIsMinLastChanged;
};
}