Added running log panel in the below screen

This commit is contained in:
Ankitkumar Satapara
2026-04-19 18:24:36 +05:30
parent 1b0ad452ca
commit 813c78eb40
4 changed files with 227 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -25,6 +26,8 @@ namespace Nodify.Calculator
_ => Editors.Count > 0 && SelectedEditor != null); _ => Editors.Count > 0 && SelectedEditor != null);
RunFlowCommand = new DelegateCommand(() => RunFlowCommand = new DelegateCommand(() =>
{ {
if (LogPanel.IsRunning) return;
Executor ex = new Executor(Editors.First()); Executor ex = new Executor(Editors.First());
var result = ex.PerformPreCheck(); var result = ex.PerformPreCheck();
if (!string.IsNullOrEmpty(result)) if (!string.IsNullOrEmpty(result))
@@ -33,8 +36,21 @@ namespace Nodify.Calculator
} }
else else
{ {
FlowRunner runner = new FlowRunner(ex); LogPanel.LogEntries.Clear();
runner.ShowDialog(); LogPanel.IsOpen = true;
LogPanel.IsRunning = true;
ex.OnLogMe += LogPanel.WriteLog;
Task.Run(() =>
{
try
{
ex.Execute();
}
finally
{
Application.Current?.Dispatcher.Invoke(() => LogPanel.IsRunning = false);
}
});
} }
}); });
SaveFileCommand = new DelegateCommand(() => SaveFileCommand = new DelegateCommand(() =>
@@ -127,5 +143,7 @@ namespace Nodify.Calculator
get => _autoSelectNewEditor; get => _autoSelectNewEditor;
set => SetProperty(ref _autoSelectNewEditor, value); set => SetProperty(ref _autoSelectNewEditor, value);
} }
public LogPanelViewModel LogPanel { get; } = new LogPanelViewModel();
} }
} }

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.ObjectModel;
using System.Windows.Media;
namespace Nodify.Calculator
{
public class LogEntry
{
public string Timestamp { get; set; }
public string Level { get; set; }
public string Message { get; set; }
public Brush Color { get; set; }
}
public class LogPanelViewModel : ObservableObject
{
private bool _isOpen;
public bool IsOpen
{
get => _isOpen;
set => SetProperty(ref _isOpen, value);
}
private bool _isRunning;
public bool IsRunning
{
get => _isRunning;
set => SetProperty(ref _isRunning, value);
}
public ObservableCollection<LogEntry> LogEntries { get; } = new ObservableCollection<LogEntry>();
public INodifyCommand ClearLogsCommand { get; }
public INodifyCommand ClosePanelCommand { get; }
public LogPanelViewModel()
{
ClearLogsCommand = new DelegateCommand(() => LogEntries.Clear());
ClosePanelCommand = new DelegateCommand(() => IsOpen = false);
}
public void WriteLog(string message, logType logtype = logType.Information)
{
Brush color;
switch (logtype)
{
case logType.Warning:
color = Brushes.Orange;
break;
case logType.Error:
color = Brushes.OrangeRed;
break;
default:
color = Brushes.White;
break;
}
var entry = new LogEntry
{
Timestamp = DateTime.Now.ToString("HH:mm:ss"),
Level = logtype.ToString(),
Message = message,
Color = color
};
if (System.Windows.Application.Current?.Dispatcher.CheckAccess() == true)
{
LogEntries.Add(entry);
}
else
{
System.Windows.Application.Current?.Dispatcher.Invoke(() => LogEntries.Add(entry));
}
}
}
}

View File

@@ -51,7 +51,14 @@
</Window.Resources> </Window.Resources>
<Grid> <Grid>
<shared:TabControlEx ItemsSource="{Binding Editors}" <Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="0" />
</Grid.RowDefinitions>
<shared:TabControlEx Grid.Row="0"
ItemsSource="{Binding Editors}"
SelectedItem="{Binding SelectedEditor}" SelectedItem="{Binding SelectedEditor}"
AddTabCommand="{Binding AddEditorCommand}" AddTabCommand="{Binding AddEditorCommand}"
AutoScrollToEnd="{Binding AutoSelectNewEditor}"> AutoScrollToEnd="{Binding AutoSelectNewEditor}">
@@ -70,7 +77,110 @@
</shared:TabControlEx.ItemContainerStyle> </shared:TabControlEx.ItemContainerStyle>
</shared:TabControlEx> </shared:TabControlEx>
<Expander Header="Click to hide/show" <!-- Log Panel -->
<Border Grid.Row="1" Height="3" Cursor="SizeNS"
Background="Transparent">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding LogPanel.IsOpen}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<GridSplitter HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#FF3F3F46"
ResizeBehavior="PreviousAndNext"
ResizeDirection="Rows" />
</Border>
<Border Grid.Row="2" Background="#FF1E1E1E" BorderBrush="#FF3F3F46" BorderThickness="0,1,0,0">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Height" Value="180" />
<Style.Triggers>
<DataTrigger Binding="{Binding LogPanel.IsOpen}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header bar -->
<Border Grid.Row="0" Background="#FF2D2D30" BorderBrush="#FF3F3F46" BorderThickness="0,0,0,1">
<DockPanel Margin="8,0">
<TextBlock Text="⚡ Output" VerticalAlignment="Center" Foreground="#FFDCDCDC" FontWeight="SemiBold" FontSize="12" />
<TextBlock VerticalAlignment="Center" Margin="10,0,0,0" Foreground="#FF888888" FontSize="11">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="" />
<Style.Triggers>
<DataTrigger Binding="{Binding LogPanel.IsRunning}" Value="True">
<Setter Property="Text" Value="● Running..." />
<Setter Property="Foreground" Value="#FF4EC9B0" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="🗑 Clear" Command="{Binding LogPanel.ClearLogsCommand}"
Background="Transparent" Foreground="#FFAAAAAA" BorderThickness="0"
Padding="6,2" FontSize="11" Cursor="Hand" Margin="0,0,4,0" />
<Button Content="✕" Command="{Binding LogPanel.ClosePanelCommand}"
Background="Transparent" Foreground="#FFAAAAAA" BorderThickness="0"
Padding="6,2" FontSize="11" Cursor="Hand" />
</StackPanel>
</DockPanel>
</Border>
<!-- Log entries -->
<ListBox Grid.Row="1" x:Name="LogListBox"
ItemsSource="{Binding LogPanel.LogEntries}"
Background="#FF1E1E1E" BorderThickness="0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
VirtualizingStackPanel.IsVirtualizing="True"
FontFamily="Consolas" FontSize="12">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="8,1" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="NoWrap">
<Run Text="{Binding Timestamp, Mode=OneTime}" Foreground="#FF608B4E" />
<Run Text=" " />
<Run Text="{Binding Message, Mode=OneTime}" Foreground="{Binding Color, Mode=OneTime}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Border>
<Expander Grid.Row="0" Header="Click to hide/show"
IsExpanded="False" IsExpanded="False"
Margin="10" Margin="10"
HorizontalAlignment="Left" HorizontalAlignment="Left"

View File

@@ -1,7 +1,9 @@
using Nodify.Interactivity; using Nodify.Interactivity;
using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
namespace Nodify.Calculator namespace Nodify.Calculator
@@ -20,6 +22,23 @@ namespace Nodify.Calculator
(KeyboardFocusChangedEventHandler)OnPreviewGotKeyboardFocus); (KeyboardFocusChangedEventHandler)OnPreviewGotKeyboardFocus);
Closing += MainWindow_Closing; Closing += MainWindow_Closing;
// Auto-scroll log list to bottom when new entries are added
Loaded += (_, __) =>
{
if (DataContext is ApplicationViewModel appVm)
{
((INotifyCollectionChanged)appVm.LogPanel.LogEntries).CollectionChanged += (s, e) =>
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
var listBox = FindName("LogListBox") as ListBox;
if (listBox != null && appVm.LogPanel.LogEntries.Count > 0)
listBox.ScrollIntoView(appVm.LogPanel.LogEntries[appVm.LogPanel.LogEntries.Count - 1]);
}
};
}
};
} }
private void MainWindow_Closing(object sender, CancelEventArgs e) private void MainWindow_Closing(object sender, CancelEventArgs e)