Add error handling to graph and equations (#827)

* add error handling

* Handle regraphing on certain errors

* Fix high contrast

* Hide KGF button in error state
This commit is contained in:
Pepe Rivera 2019-12-03 14:41:39 -08:00 committed by Eric Wong
parent 3ca4f4ffa7
commit 89c3fc3e4d
14 changed files with 397 additions and 202 deletions

View File

@ -74,6 +74,8 @@
<SolidColorBrush x:Key="EquationTextBoxTransparentBackgroundBrush" Color="Transparent"/> <SolidColorBrush x:Key="EquationTextBoxTransparentBackgroundBrush" Color="Transparent"/>
<SolidColorBrush x:Key="EquationBoxBorderBrush" Color="{ThemeResource TextControlBackground}"/> <SolidColorBrush x:Key="EquationBoxBorderBrush" Color="{ThemeResource TextControlBackground}"/>
<SolidColorBrush x:Key="EquationButtonOverlayBackgroundBrush" Color="White"/> <SolidColorBrush x:Key="EquationButtonOverlayBackgroundBrush" Color="White"/>
<SolidColorBrush x:Key="EquationBoxErrorBackgroundBrush" Color="#33EB5757"/>
<SolidColorBrush x:Key="EquationBoxErrorBorderBrush" Color="#FFEB5757"/>
<SolidColorBrush x:Key="EquationButtonHideLineBackgroundBrush" <SolidColorBrush x:Key="EquationButtonHideLineBackgroundBrush"
Opacity="0.4" Opacity="0.4"
Color="#FFFFFF"/> Color="#FFFFFF"/>
@ -166,6 +168,8 @@
<SolidColorBrush x:Key="EquationBoxHoverButtonForegroundBrush" Color="{ThemeResource SystemBaseHighColor}"/> <SolidColorBrush x:Key="EquationBoxHoverButtonForegroundBrush" Color="{ThemeResource SystemBaseHighColor}"/>
<SolidColorBrush x:Key="EquationBoxBorderBrush" Color="{ThemeResource TextControlBackground}"/> <SolidColorBrush x:Key="EquationBoxBorderBrush" Color="{ThemeResource TextControlBackground}"/>
<SolidColorBrush x:Key="EquationButtonOverlayBackgroundBrush" Color="Black"/> <SolidColorBrush x:Key="EquationButtonOverlayBackgroundBrush" Color="Black"/>
<SolidColorBrush x:Key="EquationBoxErrorBackgroundBrush" Color="#33EB5757"/>
<SolidColorBrush x:Key="EquationBoxErrorBorderBrush" Color="#FFEB5757"/>
<SolidColorBrush x:Key="EquationButtonHideLineBackgroundBrush" <SolidColorBrush x:Key="EquationButtonHideLineBackgroundBrush"
Opacity="0.4" Opacity="0.4"
Color="#000000"/> Color="#000000"/>
@ -224,6 +228,8 @@
<SolidColorBrush x:Key="AppControlTransparentButtonBackgroundBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/> <SolidColorBrush x:Key="AppControlTransparentButtonBackgroundBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/>
<SolidColorBrush x:Key="EquationButtonHideLineBackgroundBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/> <SolidColorBrush x:Key="EquationButtonHideLineBackgroundBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/>
<SolidColorBrush x:Key="EquationButtonOverlayBackgroundBrush" Color="Transparent"/> <SolidColorBrush x:Key="EquationButtonOverlayBackgroundBrush" Color="Transparent"/>
<SolidColorBrush x:Key="EquationBoxErrorBackgroundBrush" Color="{ThemeResource SystemColorButtonFaceColor}"/>
<SolidColorBrush x:Key="EquationBoxErrorBorderBrush" Color="{ThemeResource SystemColorButtonTextColor}"/>
<SolidColorBrush x:Key="EquationButtonHideLineForegroundBrush" Color="{StaticResource SystemColorGrayTextColor}"/> <SolidColorBrush x:Key="EquationButtonHideLineForegroundBrush" Color="{StaticResource SystemColorGrayTextColor}"/>
<!-- TODO: Figure out what colors we can use in high contrast --> <!-- TODO: Figure out what colors we can use in high contrast -->
<SolidColorBrush x:Key="EquationBrush1" Color="{ThemeResource SystemColorGrayTextColor}"/> <SolidColorBrush x:Key="EquationBrush1" Color="{ThemeResource SystemColorGrayTextColor}"/>
@ -1687,7 +1693,7 @@
</Setter> </Setter>
</Style> </Style>
<Style x:Key="MathRichEdit_EquationTextBoxStyle" TargetType="Controls:MathRichEditBox"> <Style x:Key="MathRichEditBoxStyle" TargetType="Controls:MathRichEditBox">
<Setter Property="Foreground" Value="{ThemeResource TextControlForeground}"/> <Setter Property="Foreground" Value="{ThemeResource TextControlForeground}"/>
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
<Setter Property="ContentLinkForegroundColor" Value="{ThemeResource ContentLinkForegroundColor}"/> <Setter Property="ContentLinkForegroundColor" Value="{ThemeResource ContentLinkForegroundColor}"/>
@ -1883,24 +1889,36 @@
<VisualStateManager.VisualStateGroups> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates"> <VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"> <VisualState x:Name="Normal">
<Storyboard> <Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackground}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="BorderBrush"> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource EquationBoxBorderBrush}"/> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource EquationBoxBorderBrush}"/>
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
</VisualState> </VisualState>
<VisualState x:Name="Error">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource EquationBoxErrorBorderBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource EquationBoxErrorBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ErrorIcon" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver"> <VisualState x:Name="PointerOver">
<Storyboard> <Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackground}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="BorderBrush"> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EquationColor}"/> <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EquationColor}"/>
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
@ -1925,6 +1943,53 @@
</DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame> </DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ErrorIcon" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverError">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EquationColor}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="EquationBoxBorder" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource EquationBoxErrorBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ColorChooserButton" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FunctionButton" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RemoveButton" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ErrorIcon" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
</VisualState> </VisualState>
@ -1965,11 +2030,17 @@
</DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame> </DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames> </ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ErrorIcon" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard> </Storyboard>
</VisualState> </VisualState>
<VisualState x:Name="ButtonCollapsed"/> <VisualState x:Name="ButtonCollapsed"/>
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
<ToggleButton x:Name="EquationButton" <ToggleButton x:Name="EquationButton"
@ -2095,11 +2166,11 @@
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Controls:MathRichEditBox x:Name="EquationTextBox" <Controls:MathRichEditBox x:Name="MathRichEditBox"
MinHeight="44" MinHeight="44"
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Style="{StaticResource MathRichEdit_EquationTextBoxStyle}" Style="{StaticResource MathRichEditBoxStyle}"
BorderThickness="0" BorderThickness="0"
FontFamily="{TemplateBinding FontFamily}" FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}" FontSize="{TemplateBinding FontSize}"
@ -2124,6 +2195,15 @@
Content="&#xE10A;" Content="&#xE10A;"
IsTabStop="False" IsTabStop="False"
Visibility="Collapsed"/> Visibility="Collapsed"/>
<FontIcon x:Name="ErrorIcon"
Grid.Column="3"
MinWidth="34"
VerticalAlignment="Stretch"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
AutomationProperties.AccessibilityView="Raw"
Glyph="&#xE783;"
FontSize="16"
Visibility="Collapsed"/>
<Button x:Name="RemoveButton" <Button x:Name="RemoveButton"
x:Uid="removeButton" x:Uid="removeButton"
Grid.Column="3" Grid.Column="3"

View File

@ -24,13 +24,13 @@ using namespace Windows::UI::Xaml::Controls::Primitives;
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationColor); DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationColor);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, ColorChooserFlyout); DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, ColorChooserFlyout);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationButtonContentIndex); DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationButtonContentIndex);
DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, HasError);
void EquationTextBox::OnApplyTemplate() void EquationTextBox::OnApplyTemplate()
{ {
m_equationButton = dynamic_cast<ToggleButton ^>(GetTemplateChild("EquationButton")); m_equationButton = dynamic_cast<ToggleButton ^>(GetTemplateChild("EquationButton"));
m_kgfEquationButton = dynamic_cast<Button ^>(GetTemplateChild("KGFEquationButton")); m_kgfEquationButton = dynamic_cast<Button ^>(GetTemplateChild("KGFEquationButton"));
m_richEditBox = dynamic_cast<MathRichEditBox ^>(GetTemplateChild("EquationTextBox")); m_richEditBox = dynamic_cast<MathRichEditBox ^>(GetTemplateChild("MathRichEditBox"));
m_deleteButton = dynamic_cast<Button ^>(GetTemplateChild("DeleteButton")); m_deleteButton = dynamic_cast<Button ^>(GetTemplateChild("DeleteButton"));
m_removeButton = dynamic_cast<Button ^>(GetTemplateChild("RemoveButton")); m_removeButton = dynamic_cast<Button ^>(GetTemplateChild("RemoveButton"));
m_functionButton = dynamic_cast<Button ^>(GetTemplateChild("FunctionButton")); m_functionButton = dynamic_cast<Button ^>(GetTemplateChild("FunctionButton"));
@ -127,7 +127,7 @@ void EquationTextBox::OnKeyDown(KeyRoutedEventArgs ^ e)
void EquationTextBox::OnLostFocus(RoutedEventArgs ^ e) void EquationTextBox::OnLostFocus(RoutedEventArgs ^ e)
{ {
if (!m_richEditBox->ContextFlyout->IsOpen) if (m_richEditBox != nullptr && !m_richEditBox->ContextFlyout->IsOpen)
{ {
EquationSubmitted(this, ref new RoutedEventArgs()); EquationSubmitted(this, ref new RoutedEventArgs());
if (m_functionButton && m_richEditBox->MathText != L"") if (m_functionButton && m_richEditBox->MathText != L"")
@ -168,6 +168,7 @@ void EquationTextBox::OnRichEditBoxLostFocus(Object ^ sender, RoutedEventArgs ^
{ {
m_HasFocus = false; m_HasFocus = false;
} }
UpdateCommonVisualState(); UpdateCommonVisualState();
UpdateDeleteButtonVisualState(); UpdateDeleteButtonVisualState();
} }
@ -259,26 +260,38 @@ void EquationTextBox::UpdateCommonVisualState()
{ {
state = "Focused"; state = "Focused";
} }
else if ((m_isPointerOver && HasError) || (m_isColorChooserFlyoutOpen && HasError))
{
state = "PointerOverError";
}
else if (m_isPointerOver || m_isColorChooserFlyoutOpen) else if (m_isPointerOver || m_isColorChooserFlyoutOpen)
{ {
state = "PointerOver"; state = "PointerOver";
} }
else if (HasError)
{
state = "Error";
}
VisualStateManager::GoToState(this, state, true); VisualStateManager::GoToState(this, state, true);
} }
void EquationTextBox::OnHasErrorPropertyChanged(bool, bool)
{
UpdateCommonVisualState();
}
Platform::String ^ EquationTextBox::GetEquationText() Platform::String ^ EquationTextBox::GetEquationText()
{ {
String ^ text; String ^ text;
if (m_richEditBox != nullptr) if (m_richEditBox != nullptr)
{ {
// Clear formatting since the graph control doesn't work with bold/italic/underlines // Clear formatting since the graph control doesn't work with bold/underlines
ITextRange ^ range = m_richEditBox->TextDocument->GetRange(0, m_richEditBox->TextDocument->Selection->EndPosition); ITextRange ^ range = m_richEditBox->TextDocument->GetRange(0, m_richEditBox->TextDocument->Selection->EndPosition);
if (range != nullptr) if (range != nullptr)
{ {
range->CharacterFormat->Bold = FormatEffect::Off; range->CharacterFormat->Bold = FormatEffect::Off;
range->CharacterFormat->Italic = FormatEffect::Off;
range->CharacterFormat->Underline = UnderlineType::None; range->CharacterFormat->Underline = UnderlineType::None;
} }

View File

@ -22,6 +22,7 @@ namespace CalculatorApp
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::SolidColorBrush^, EquationColor); DEPENDENCY_PROPERTY(Windows::UI::Xaml::Media::SolidColorBrush^, EquationColor);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::Flyout^, ColorChooserFlyout); DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::Flyout^, ColorChooserFlyout);
DEPENDENCY_PROPERTY(Platform::String ^, EquationButtonContentIndex); DEPENDENCY_PROPERTY(Platform::String ^, EquationButtonContentIndex);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, HasError);
PROPERTY_R(bool, HasFocus); PROPERTY_R(bool, HasFocus);
@ -61,6 +62,8 @@ namespace CalculatorApp
void OnColorFlyoutOpened(Platform::Object^ sender, Platform::Object^ e); void OnColorFlyoutOpened(Platform::Object^ sender, Platform::Object^ e);
void OnColorFlyoutClosed(Platform::Object^ sender, Platform::Object^ e); void OnColorFlyoutClosed(Platform::Object^ sender, Platform::Object^ e);
void OnHasErrorPropertyChanged(bool oldValue, bool newValue);
CalculatorApp::Controls::MathRichEditBox^ m_richEditBox; CalculatorApp::Controls::MathRichEditBox^ m_richEditBox;
Windows::UI::Xaml::Controls::Primitives::ToggleButton^ m_equationButton; Windows::UI::Xaml::Controls::Primitives::ToggleButton^ m_equationButton;
Windows::UI::Xaml::Controls::Button^ m_kgfEquationButton; Windows::UI::Xaml::Controls::Button^ m_kgfEquationButton;

View File

@ -54,6 +54,7 @@
EquationButtonContentIndex="{x:Bind FunctionLabelIndex, Mode=OneWay}" EquationButtonContentIndex="{x:Bind FunctionLabelIndex, Mode=OneWay}"
EquationSubmitted="InputTextBox_Submitted" EquationSubmitted="InputTextBox_Submitted"
GotFocus="InputTextBox_GotFocus" GotFocus="InputTextBox_GotFocus"
HasError="{x:Bind GraphEquation.HasGraphError, Mode=OneWay}"
Loaded="EquationTextBoxLoaded" Loaded="EquationTextBoxLoaded"
LostFocus="InputTextBox_LostFocus" LostFocus="InputTextBox_LostFocus"
RemoveButtonClicked="EquationTextBox_RemoveButtonClicked" RemoveButtonClicked="EquationTextBox_RemoveButtonClicked"

View File

@ -110,17 +110,47 @@ void GraphingCalculator::GraphingCalculator_DataContextChanged(FrameworkElement
void GraphingCalculator::OnEquationsVectorChanged(IObservableVector<EquationViewModel ^> ^ sender, IVectorChangedEventArgs ^ event) void GraphingCalculator::OnEquationsVectorChanged(IObservableVector<EquationViewModel ^> ^ sender, IVectorChangedEventArgs ^ event)
{ {
if (event->CollectionChange != ::CollectionChange::ItemChanged) // If an item is already added to the graph, changing it should automatically trigger a graph update
if (event->CollectionChange == ::CollectionChange::ItemChanged)
{ {
GraphingControl->Equations->Clear(); return;
for (auto equationViewModel : ViewModel->Equations)
{
GraphingControl->Equations->Append(equationViewModel->GraphEquation);
}
GraphingControl->PlotGraph();
} }
// Do not plot the graph if we are removing an empty equation, just remove it
if (event->CollectionChange == ::CollectionChange::ItemRemoved)
{
auto itemToRemove = GraphingControl->Equations->GetAt(event->Index);
if (itemToRemove->Expression->IsEmpty())
{
GraphingControl->Equations->RemoveAt(event->Index);
return;
}
}
// Do not plot the graph if we are adding an empty equation, just add it
if (event->CollectionChange == ::CollectionChange::ItemInserted)
{
auto itemToAdd = sender->GetAt(event->Index);
if (itemToAdd->Expression->IsEmpty())
{
GraphingControl->Equations->Append(itemToAdd->GraphEquation);
return;
}
}
// We are either adding or removing a valid equation, or resetting the collection. We will need to plot the graph
GraphingControl->Equations->Clear();
for (auto equationViewModel : ViewModel->Equations)
{
GraphingControl->Equations->Append(equationViewModel->GraphEquation);
}
GraphingControl->PlotGraph();
} }
void GraphingCalculator::OnTracePointChanged(Windows::Foundation::Point newPoint) void GraphingCalculator::OnTracePointChanged(Windows::Foundation::Point newPoint)

View File

@ -38,7 +38,6 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo
private: private:
void GraphingCalculator_DataContextChanged(Windows::UI::Xaml::FrameworkElement ^ sender, Windows::UI::Xaml::DataContextChangedEventArgs ^ args); 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 OnVariableChanged(Platform::Object ^ sender, CalculatorApp::ViewModel::VariableChangedEventArgs args);
void OnEquationsVectorChanged( void OnEquationsVectorChanged(
Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::EquationViewModel ^> ^ sender, Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::EquationViewModel ^> ^ sender,

View File

@ -26,119 +26,6 @@
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="controls:EquationTextBox"> <ControlTemplate TargetType="controls:EquationTextBox">
<Grid> <Grid>
<Grid.Resources>
<Style x:Key="KGF_EquationTextBoxStyle" TargetType="controls:MathRichEditBox">
<Setter Property="Foreground" Value="{ThemeResource TextControlForeground}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ContentLinkForegroundColor" Value="{ThemeResource ContentLinkForegroundColor}"/>
<Setter Property="ContentLinkBackgroundColor" Value="{ThemeResource ContentLinkBackgroundColor}"/>
<Setter Property="SelectionHighlightColor" Value="{ThemeResource TextControlSelectionHighlightColor}"/>
<Setter Property="BorderBrush" Value="{ThemeResource TextControlBorderBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource TextControlBorderThemeThickness}"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
<Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}"/>
<Setter Property="UseSystemFocusVisuals" Value="{ThemeResource IsApplicationFocusVisualKindReveal}"/>
<Setter Property="ContextFlyout" Value="{StaticResource TextControlCommandBarContextFlyout}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:MathRichEditBox">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled"/>
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver"/>
<VisualState x:Name="Focused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="HeaderContentPresenter"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="{ThemeResource RichEditBoxTopHeaderMargin}"
Foreground="{ThemeResource TextControlHeaderForeground}"
FontWeight="Normal"
x:DeferLoadStrategy="Lazy"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
TextWrapping="Wrap"
Visibility="Collapsed"/>
<Border x:Name="BorderElement"
Grid.Row="1"
Grid.RowSpan="1"
Grid.Column="0"
Grid.ColumnSpan="4"
MinWidth="{ThemeResource TextControlThemeMinWidth}"
MinHeight="{ThemeResource TextControlThemeMinHeight}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0"
Control.IsTemplateFocusTarget="True"
CornerRadius="{TemplateBinding CornerRadius}"/>
<ScrollViewer x:Name="ContentElement"
Grid.Row="1"
Grid.Column="0"
Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
IsTabStop="False"
IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
ZoomMode="Disabled"/>
<TextBlock x:Name="PlaceholderTextContentPresenter"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
VerticalAlignment="Center"
Foreground="{ThemeResource TextControlPlaceholderForeground}"
IsHitTestVisible="False"
Text="{TemplateBinding PlaceholderText}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}"/>
<ContentPresenter x:Name="DescriptionPresenter"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="4"
Background="Transparent"
Foreground="{ThemeResource SystemControlDescriptionTextForegroundBrush}"
x:Load="False"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Description}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
@ -185,12 +72,12 @@
</Button.Resources> </Button.Resources>
</Button> </Button>
<controls:MathRichEditBox x:Name="EquationTextBox" <controls:MathRichEditBox x:Name="MathRichEditBox"
Grid.Column="1" Grid.Column="1"
MinHeight="44" MinHeight="44"
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Style="{StaticResource MathRichEdit_EquationTextBoxStyle}" Style="{StaticResource MathRichEditBoxStyle}"
Background="Transparent" Background="Transparent"
BorderThickness="0" BorderThickness="0"
FontFamily="{TemplateBinding FontFamily}" FontFamily="{TemplateBinding FontFamily}"

View File

@ -26,7 +26,13 @@ namespace GraphControl
DependencyProperty ^ Equation::s_isLineEnabledProperty; DependencyProperty ^ Equation::s_isLineEnabledProperty;
static constexpr auto s_propertyName_IsLineEnabled = L"IsLineEnabled"; static constexpr auto s_propertyName_IsLineEnabled = L"IsLineEnabled";
DependencyProperty ^ Equation::s_xInterceptProperty; DependencyProperty ^ Equation::s_hasGraphErrorProperty;
static constexpr auto s_propertyName_HasGraphError = L"HasGraphError";
DependencyProperty ^ Equation::s_isValidatedProperty;
static constexpr auto s_propertyName_IsValidated = L"IsValidated";
DependencyProperty ^ Equation::s_xInterceptProperty;
static constexpr auto s_propertyName_XIntercept = L"XIntercept"; static constexpr auto s_propertyName_XIntercept = L"XIntercept";
DependencyProperty ^ Equation::s_yInterceptProperty; DependencyProperty ^ Equation::s_yInterceptProperty;
@ -79,6 +85,8 @@ namespace GraphControl
String ^ Expression = StringReference(s_propertyName_Expression); String ^ Expression = StringReference(s_propertyName_Expression);
String ^ LineColor = StringReference(s_propertyName_LineColor); String ^ LineColor = StringReference(s_propertyName_LineColor);
String ^ IsLineEnabled = StringReference(s_propertyName_IsLineEnabled); String ^ IsLineEnabled = StringReference(s_propertyName_IsLineEnabled);
String ^ HasGraphError = StringReference(s_propertyName_HasGraphError);
String ^ IsValidated = StringReference(s_propertyName_IsValidated);
String ^ XIntercept = StringReference(s_propertyName_XIntercept); String ^ XIntercept = StringReference(s_propertyName_XIntercept);
String ^ YIntercept = StringReference(s_propertyName_YIntercept); String ^ YIntercept = StringReference(s_propertyName_YIntercept);
String ^ Parity = StringReference(s_propertyName_Parity); String ^ Parity = StringReference(s_propertyName_Parity);
@ -129,6 +137,24 @@ namespace GraphControl
ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged))); ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
} }
if (!s_hasGraphErrorProperty)
{
s_hasGraphErrorProperty = DependencyProperty::Register(
EquationProperties::HasGraphError,
bool ::typeid,
Equation::typeid,
ref new PropertyMetadata(false, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
}
if (!s_isValidatedProperty)
{
s_isValidatedProperty = DependencyProperty::Register(
EquationProperties::IsValidated,
bool ::typeid,
Equation::typeid,
ref new PropertyMetadata(false, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
}
if (!s_xInterceptProperty) if (!s_xInterceptProperty)
{ {
s_xInterceptProperty = DependencyProperty::Register( s_xInterceptProperty = DependencyProperty::Register(
@ -354,6 +380,14 @@ namespace GraphControl
{ {
propertyName = EquationProperties::AnalysisError; propertyName = EquationProperties::AnalysisError;
} }
else if (args->Property == s_hasGraphErrorProperty)
{
propertyName = EquationProperties::HasGraphError;
}
else if (args->Property == s_isValidatedProperty)
{
propertyName = EquationProperties::IsValidated;
}
eq->PropertyChanged(eq, propertyName); eq->PropertyChanged(eq, propertyName);
} }
@ -398,4 +432,9 @@ namespace GraphControl
{ {
return L""s; return L""s;
} }
bool Equation::IsGraphableEquation()
{
return !Expression->IsEmpty() && IsLineEnabled && !HasGraphError;
}
} }

View File

@ -91,6 +91,44 @@ namespace GraphControl
#pragma endregion #pragma endregion
#pragma region bool HasGraphError DependencyProperty
static property Windows::UI::Xaml::DependencyProperty ^ HasGraphErrorProperty { Windows::UI::Xaml::DependencyProperty ^ get() { return s_hasGraphErrorProperty; } }
property bool HasGraphError
{
bool get()
{
return static_cast<bool>(GetValue(s_hasGraphErrorProperty));
}
internal:
void set(bool value)
{
SetValue(s_hasGraphErrorProperty, value);
}
}
#pragma endregion
#pragma region bool IsValidated DependencyProperty
static property Windows::UI::Xaml::DependencyProperty ^ IsValidatedProperty { Windows::UI::Xaml::DependencyProperty ^ get() { return s_isValidatedProperty; } }
property bool IsValidated
{
bool get()
{
return static_cast<bool>(GetValue(s_isValidatedProperty));
}
internal:
void set(bool value)
{
SetValue(s_isValidatedProperty, value);
}
}
#pragma endregion
#pragma region Key Graph Features #pragma region Key Graph Features
@ -108,7 +146,7 @@ namespace GraphControl
{ {
return static_cast<Platform::String^>(GetValue(s_xInterceptProperty)); return static_cast<Platform::String^>(GetValue(s_xInterceptProperty));
} }
void set(Platform::String^ value) internal: void set(Platform::String^ value)
{ {
SetValue(s_xInterceptProperty, value); SetValue(s_xInterceptProperty, value);
} }
@ -129,7 +167,7 @@ namespace GraphControl
{ {
return static_cast<Platform::String^>(GetValue(s_yInterceptProperty)); return static_cast<Platform::String^>(GetValue(s_yInterceptProperty));
} }
void set(Platform::String^ value) internal: void set(Platform::String^ value)
{ {
SetValue(s_yInterceptProperty, value); SetValue(s_yInterceptProperty, value);
} }
@ -150,7 +188,7 @@ namespace GraphControl
{ {
return static_cast<int>(GetValue(s_parityProperty)); return static_cast<int>(GetValue(s_parityProperty));
} }
void set(int value) internal: void set(int value)
{ {
SetValue(s_parityProperty, value); SetValue(s_parityProperty, value);
} }
@ -171,7 +209,7 @@ namespace GraphControl
{ {
return static_cast<int>(GetValue(s_periodicityDirectionProperty)); return static_cast<int>(GetValue(s_periodicityDirectionProperty));
} }
void set(int value) internal: void set(int value)
{ {
SetValue(s_periodicityDirectionProperty, value); SetValue(s_periodicityDirectionProperty, value);
} }
@ -192,7 +230,7 @@ namespace GraphControl
{ {
return static_cast<Platform::String ^>(GetValue(s_periodicityExpressionProperty)); return static_cast<Platform::String ^>(GetValue(s_periodicityExpressionProperty));
} }
void set(Platform::String ^ value) internal: void set(Platform::String ^ value)
{ {
SetValue(s_periodicityExpressionProperty, value); SetValue(s_periodicityExpressionProperty, value);
} }
@ -213,7 +251,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_minimaProperty)); return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_minimaProperty));
} }
void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value) internal: void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value)
{ {
SetValue(s_minimaProperty, value); SetValue(s_minimaProperty, value);
} }
@ -234,7 +272,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_maximaProperty)); return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_maximaProperty));
} }
void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value) internal: void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value)
{ {
SetValue(s_maximaProperty, value); SetValue(s_maximaProperty, value);
} }
@ -255,7 +293,7 @@ namespace GraphControl
{ {
return static_cast<Platform::String^>(GetValue(s_domainProperty)); return static_cast<Platform::String^>(GetValue(s_domainProperty));
} }
void set(Platform::String^ value) internal: void set(Platform::String^ value)
{ {
SetValue(s_domainProperty, value); SetValue(s_domainProperty, value);
} }
@ -276,7 +314,7 @@ namespace GraphControl
{ {
return static_cast<Platform::String^>(GetValue(s_rangeProperty)); return static_cast<Platform::String^>(GetValue(s_rangeProperty));
} }
void set(Platform::String^ value) internal: void set(Platform::String^ value)
{ {
SetValue(s_rangeProperty, value); SetValue(s_rangeProperty, value);
} }
@ -297,7 +335,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_inflectionPointsProperty)); return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_inflectionPointsProperty));
} }
void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value) internal: void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value)
{ {
SetValue(s_inflectionPointsProperty, value); SetValue(s_inflectionPointsProperty, value);
} }
@ -318,7 +356,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::String ^> ^>(GetValue(s_monotonicityProperty)); return static_cast<Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::String ^> ^>(GetValue(s_monotonicityProperty));
} }
void set(Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::String ^> ^ value) internal: void set(Windows::Foundation::Collections::IObservableMap<Platform::String^, Platform::String ^> ^ value)
{ {
SetValue(s_monotonicityProperty, value); SetValue(s_monotonicityProperty, value);
} }
@ -339,7 +377,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_verticalAsymptotesProperty)); return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_verticalAsymptotesProperty));
} }
void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value) internal: void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value)
{ {
SetValue(s_verticalAsymptotesProperty, value); SetValue(s_verticalAsymptotesProperty, value);
} }
@ -360,7 +398,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_horizontalAsymptotesProperty)); return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_horizontalAsymptotesProperty));
} }
void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value) internal: void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value)
{ {
SetValue(s_horizontalAsymptotesProperty, value); SetValue(s_horizontalAsymptotesProperty, value);
} }
@ -381,7 +419,7 @@ namespace GraphControl
{ {
return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_obliqueAsymptotesProperty)); return static_cast<Windows::Foundation::Collections::IVector<Platform::String^> ^>(GetValue(s_obliqueAsymptotesProperty));
} }
void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value) internal: void set(Windows::Foundation::Collections::IVector<Platform::String^> ^ value)
{ {
SetValue(s_obliqueAsymptotesProperty, value); SetValue(s_obliqueAsymptotesProperty, value);
} }
@ -402,7 +440,7 @@ namespace GraphControl
{ {
return static_cast<int>(GetValue(s_tooComplexFeaturesProperty)); return static_cast<int>(GetValue(s_tooComplexFeaturesProperty));
} }
void set(int value) internal: void set(int value)
{ {
SetValue(s_tooComplexFeaturesProperty, value); SetValue(s_tooComplexFeaturesProperty, value);
} }
@ -423,7 +461,7 @@ namespace GraphControl
{ {
return static_cast<int>(GetValue(s_analysisErrorProperty)); return static_cast<int>(GetValue(s_analysisErrorProperty));
} }
void set(int value) internal: void set(int value)
{ {
SetValue(s_analysisErrorProperty, value); SetValue(s_analysisErrorProperty, value);
} }
@ -434,6 +472,7 @@ namespace GraphControl
internal : event PropertyChangedEventHandler ^ PropertyChanged; internal : event PropertyChangedEventHandler ^ PropertyChanged;
std::wstring GetRequest(); std::wstring GetRequest();
bool IsGraphableEquation();
private: private:
static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args); static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
@ -446,6 +485,8 @@ namespace GraphControl
static Windows::UI::Xaml::DependencyProperty ^ s_expressionProperty; static Windows::UI::Xaml::DependencyProperty ^ s_expressionProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_lineColorProperty; static Windows::UI::Xaml::DependencyProperty ^ s_lineColorProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_isLineEnabledProperty; static Windows::UI::Xaml::DependencyProperty ^ s_isLineEnabledProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_hasGraphErrorProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_isValidatedProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_xInterceptProperty; static Windows::UI::Xaml::DependencyProperty ^ s_xInterceptProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_yInterceptProperty; static Windows::UI::Xaml::DependencyProperty ^ s_yInterceptProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_parityProperty; static Windows::UI::Xaml::DependencyProperty ^ s_parityProperty;

View File

@ -7,7 +7,7 @@
namespace GraphControl namespace GraphControl
{ {
delegate void EquationChangedEventHandler(); delegate void EquationChangedEventHandler(Equation ^ sender);
delegate void VisibilityChangedEventHandler(Equation ^ sender); delegate void VisibilityChangedEventHandler(Equation ^ sender);
public public
@ -151,19 +151,19 @@ public
event EquationChangedEventHandler ^ EquationLineEnabledChanged; event EquationChangedEventHandler ^ EquationLineEnabledChanged;
private: private:
void OnEquationPropertyChanged(GraphControl::Equation ^, Platform::String ^ propertyName) void OnEquationPropertyChanged(GraphControl::Equation ^ sender, Platform::String ^ propertyName)
{ {
if (propertyName == EquationProperties::LineColor) if (propertyName == EquationProperties::LineColor)
{ {
EquationStyleChanged(); EquationStyleChanged(sender);
} }
else if (propertyName == EquationProperties::Expression) else if (propertyName == EquationProperties::Expression)
{ {
EquationChanged(); EquationChanged(sender);
} }
else if (propertyName == EquationProperties::IsLineEnabled) else if (propertyName == EquationProperties::IsLineEnabled)
{ {
EquationLineEnabledChanged(); EquationLineEnabledChanged(sender);
} }
} }

View File

@ -62,7 +62,7 @@ namespace GraphControl
, m_Moving{ false } , m_Moving{ false }
{ {
m_solver->ParsingOptions().SetFormatType(s_defaultFormatType); m_solver->ParsingOptions().SetFormatType(s_defaultFormatType);
m_solver->FormatOptions().SetFormatType(FormatType::MathML); m_solver->FormatOptions().SetFormatType(s_defaultFormatType);
m_solver->FormatOptions().SetMathMLPrefix(wstring(L"mml")); m_solver->FormatOptions().SetMathMLPrefix(wstring(L"mml"));
DefaultStyleKey = StringReference(s_defaultStyleKey); DefaultStyleKey = StringReference(s_defaultStyleKey);
@ -144,7 +144,7 @@ namespace GraphControl
m_renderMain = ref new RenderMain(swapChainPanel); m_renderMain = ref new RenderMain(swapChainPanel);
} }
UpdateGraph(); TryUpdateGraph();
} }
void Grapher::RegisterDependencyProperties() void Grapher::RegisterDependencyProperties()
@ -229,19 +229,26 @@ namespace GraphControl
ref new EquationChangedEventHandler(this, &Grapher::OnEquationLineEnabledChanged); ref new EquationChangedEventHandler(this, &Grapher::OnEquationLineEnabledChanged);
} }
UpdateGraph(); PlotGraph();
} }
void Grapher::OnEquationChanged() void Grapher::OnEquationChanged(Equation ^ equation)
{ {
UpdateGraph(); // If the equation was previously valid, we should try to graph again in the event of the failure
bool shouldRetry = equation->IsValidated;
// Reset these properties if the equation is requesting to be graphed again
equation->HasGraphError = false;
equation->IsValidated = false;
TryPlotGraph(shouldRetry);
} }
void Grapher::OnEquationStyleChanged() void Grapher::OnEquationStyleChanged(Equation ^)
{ {
if (m_graph) if (m_graph)
{ {
UpdateGraphOptions(m_graph->GetOptions(), GetValidEquations()); UpdateGraphOptions(m_graph->GetOptions(), GetGraphableEquations());
} }
if (m_renderMain) if (m_renderMain)
@ -250,14 +257,15 @@ namespace GraphControl
} }
} }
void Grapher::OnEquationLineEnabledChanged() void Grapher::OnEquationLineEnabledChanged(Equation ^ equation)
{ {
UpdateGraph(); // If the equation is in an error state or is empty, it should not be graphed anyway.
} if (equation->HasGraphError || equation->Expression->IsEmpty())
{
return;
}
void Grapher::PlotGraph() PlotGraph();
{
UpdateGraph();
} }
void Grapher::AnalyzeEquation(Equation ^ equation) void Grapher::AnalyzeEquation(Equation ^ equation)
@ -307,13 +315,43 @@ namespace GraphControl
equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed; equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed;
} }
void Grapher::UpdateGraph() void Grapher::PlotGraph()
{
TryPlotGraph(false);
}
void Grapher::TryPlotGraph(bool shouldRetry)
{
if (TryUpdateGraph())
{
SetEquationsAsValid();
}
else
{
SetEquationErrors();
// If we failed to plot the graph, try again after the bad equations are flagged.
if (shouldRetry)
{
TryUpdateGraph();
}
}
}
bool Grapher::TryUpdateGraph()
{ {
optional<vector<shared_ptr<IEquation>>> initResult = nullopt; optional<vector<shared_ptr<IEquation>>> initResult = nullopt;
bool successful = false;
if (m_renderMain && m_graph != nullptr) if (m_renderMain && m_graph != nullptr)
{ {
auto validEqs = GetValidEquations(); unique_ptr<IExpression> graphExpression;
wstring request;
auto validEqs = GetGraphableEquations();
// Will be set to true if the previous graph should be kept in the event of an error
bool shouldKeepPreviousGraph = false;
if (!validEqs.empty()) if (!validEqs.empty())
{ {
@ -323,6 +361,11 @@ namespace GraphControl
int numValidEquations = 0; int numValidEquations = 0;
for (Equation ^ eq : validEqs) for (Equation ^ eq : validEqs)
{ {
if (eq->IsValidated)
{
shouldKeepPreviousGraph = true;
}
if (numValidEquations++ > 0) if (numValidEquations++ > 0)
{ {
ss << L"<mo>,</mo>"; ss << L"<mo>,</mo>";
@ -333,26 +376,78 @@ namespace GraphControl
ss << s_getGraphClosingTags; ss << s_getGraphClosingTags;
wstring request = ss.str(); request = ss.str();
unique_ptr<IExpression> graphExpression; }
if (graphExpression = m_solver->ParseInput(request))
if (graphExpression = m_solver->ParseInput(request))
{
initResult = m_graph->TryInitialize(graphExpression.get());
if (initResult != nullopt)
{ {
initResult = m_graph->TryInitialize(graphExpression.get()); UpdateGraphOptions(m_graph->GetOptions(), validEqs);
SetGraphArgs();
m_renderMain->Graph = m_graph;
// It is possible that the render fails, in that case fall through to explicit empty initialization
if (m_renderMain->RunRenderPass())
{
UpdateVariables();
successful = true;
}
else
{
// If we failed to render then we have already lost the previous graph
shouldKeepPreviousGraph = false;
initResult = nullopt;
}
} }
} }
if (initResult == nullopt) if (initResult == nullopt)
{ {
initResult = m_graph->TryInitialize(); // Do not re-initialize the graph to empty if there are still valid equations graphed
if (!shouldKeepPreviousGraph)
{
initResult = m_graph->TryInitialize();
if (initResult != nullopt)
{
UpdateGraphOptions(m_graph->GetOptions(), validEqs);
SetGraphArgs();
m_renderMain->Graph = m_graph;
m_renderMain->RunRenderPass();
UpdateVariables();
// Initializing an empty graph is only a success if there were no equations to graph.
successful = (validEqs.size() == 0);
}
}
} }
}
if (initResult != nullopt) // Return true if we were able to graph and render all graphable equations
return successful;
}
void Grapher::SetEquationsAsValid()
{
for (Equation ^ eq : GetGraphableEquations())
{
eq->IsValidated = true;
}
}
void Grapher::SetEquationErrors()
{
for (Equation ^ eq : GetGraphableEquations())
{
if (!eq->IsValidated)
{ {
UpdateGraphOptions(m_graph->GetOptions(), validEqs); eq->HasGraphError = true;
SetGraphArgs();
UpdateVariables();
m_renderMain->Graph = m_graph;
} }
} }
} }
@ -417,6 +512,7 @@ namespace GraphControl
void Grapher::UpdateVariables() void Grapher::UpdateVariables()
{ {
auto updatedVariables = ref new Map<String ^, double>(); auto updatedVariables = ref new Map<String ^, double>();
if (m_graph) if (m_graph)
{ {
auto graphVariables = m_graph->GetVariables(); auto graphVariables = m_graph->GetVariables();
@ -484,13 +580,13 @@ namespace GraphControl
} }
} }
vector<Equation ^> Grapher::GetValidEquations() vector<Equation ^> Grapher::GetGraphableEquations()
{ {
vector<Equation ^> validEqs; vector<Equation ^> validEqs;
for (Equation ^ eq : Equations) for (Equation ^ eq : Equations)
{ {
if (!eq->Expression->IsEmpty() && eq->IsLineEnabled) if (eq->IsGraphableEquation())
{ {
validEqs.push_back(eq); validEqs.push_back(eq);
} }
@ -501,7 +597,7 @@ namespace GraphControl
void Grapher::OnForceProportionalAxesChanged(DependencyPropertyChangedEventArgs ^ args) void Grapher::OnForceProportionalAxesChanged(DependencyPropertyChangedEventArgs ^ args)
{ {
UpdateGraph(); TryUpdateGraph();
} }
void Grapher::OnBackgroundColorChanged(const Windows::UI::Color& color) void Grapher::OnBackgroundColorChanged(const Windows::UI::Color& color)

View File

@ -171,12 +171,13 @@ public
void OnDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyProperty ^ p); void OnDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyProperty ^ p);
void OnEquationsChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args); void OnEquationsChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnEquationChanged(); void OnEquationChanged(GraphControl::Equation ^ equation);
void OnEquationStyleChanged(); void OnEquationStyleChanged(GraphControl::Equation ^ equation);
void OnEquationLineEnabledChanged(); void OnEquationLineEnabledChanged(GraphControl::Equation ^ equation);
void UpdateGraph(); bool TryUpdateGraph();
void TryPlotGraph(bool shouldRetry);
void UpdateGraphOptions(Graphing::IGraphingOptions& options, const std::vector<Equation ^>& validEqs); void UpdateGraphOptions(Graphing::IGraphingOptions& options, const std::vector<Equation ^>& validEqs);
std::vector<Equation ^> GetValidEquations(); std::vector<Equation ^> GetGraphableEquations();
void SetGraphArgs(); void SetGraphArgs();
std::shared_ptr<Graphing::IGraph> GetGraph(GraphControl::Equation ^ equation); std::shared_ptr<Graphing::IGraph> GetGraph(GraphControl::Equation ^ equation);
void UpdateVariables(); void UpdateVariables();
@ -194,6 +195,9 @@ public
void HandleTracingMovementTick(Object ^ sender, Object ^ e); void HandleTracingMovementTick(Object ^ sender, Object ^ e);
void HandleKey(bool keyDown, Windows::System::VirtualKey key); void HandleKey(bool keyDown, Windows::System::VirtualKey key);
void SetEquationsAsValid();
void SetEquationErrors();
Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^ ConvertWStringVector(std::vector<std::wstring> inVector); Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^ ConvertWStringVector(std::vector<std::wstring> inVector);
Windows::Foundation::Collections::IObservableMap<Platform::String ^, Platform::String ^> ^ ConvertWStringIntMap(std::map<std::wstring, int> inMap); Windows::Foundation::Collections::IObservableMap<Platform::String ^, Platform::String ^> ^ ConvertWStringIntMap(std::map<std::wstring, int> inMap);

View File

@ -68,8 +68,6 @@ namespace GraphControl::DX
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));
} }
} }
RunRenderPass();
} }
void RenderMain::BackgroundColor::set(Windows::UI::Color backgroundColor) void RenderMain::BackgroundColor::set(Windows::UI::Color backgroundColor)
@ -125,12 +123,16 @@ namespace GraphControl::DX
RunRenderPass(); RunRenderPass();
} }
void RenderMain::RunRenderPass() bool RenderMain::RunRenderPass()
{ {
if (Render()) bool succesful = Render();
if (succesful)
{ {
m_deviceResources.Present(); m_deviceResources.Present();
} }
return succesful;
} }
// Renders the current frame according to the current application state. // Renders the current frame according to the current application state.

View File

@ -46,7 +46,7 @@ namespace GraphControl::DX
void CreateWindowSizeDependentResources(); void CreateWindowSizeDependentResources();
void RunRenderPass(); bool RunRenderPass();
// Indicates if we are in active tracing mode (the tracing box is being used and controlled through keyboard input) // Indicates if we are in active tracing mode (the tracing box is being used and controlled through keyboard input)
property bool ActiveTracing property bool ActiveTracing