mirror of
https://github.com/Microsoft/calculator.git
synced 2025-07-30 11:38:26 -07:00
Add Graph Settings (#879)
This commit is contained in:
parent
234ac8deb3
commit
8357f5d5c5
35 changed files with 1882 additions and 195 deletions
|
@ -190,7 +190,7 @@ void ApplicationViewModel::OnCopyCommand(Object ^ parameter)
|
|||
{
|
||||
DateCalcViewModel->OnCopyCommand(parameter);
|
||||
}
|
||||
else
|
||||
else if (NavCategory::IsCalculatorViewMode(m_mode))
|
||||
{
|
||||
CalculatorViewModel->OnCopyCommand(parameter);
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
297
src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h
Normal file
297
src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h
Normal 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;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue