Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OneWare.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<Project Path="src/OneWare.CloudIntegration/OneWare.CloudIntegration.csproj" />
<Project Path="src/OneWare.Copilot/OneWare.Copilot.csproj" />
<Project Path="src/OneWare.ImageViewer/OneWare.ImageViewer.csproj" />
<Project Path="src/OneWare.MarkdownViewer/OneWare.MarkdownViewer.csproj" />
<Project Path="src/OneWare.PackageManager/OneWare.PackageManager.csproj" />
<Project Path="src\OneWare.Chat\OneWare.Chat.csproj" />
</Folder>
Expand Down
20 changes: 20 additions & 0 deletions src/OneWare.MarkdownViewer/MarkdownViewerModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
using OneWare.Essentials.Services;
using OneWare.MarkdownViewer.ViewModels;

namespace OneWare.MarkdownViewer;

public class MarkdownViewerModule : OneWareModuleBase
{
public override void RegisterServices(IServiceCollection services)
{
services.AddTransient<MarkdownEditViewModel>();
}

public override void Initialize(IServiceProvider serviceProvider)
{
serviceProvider.Resolve<IMainDockService>()
.RegisterDocumentView<MarkdownEditViewModel>(".md", ".markdown");
}
}

9 changes: 9 additions & 0 deletions src/OneWare.MarkdownViewer/OneWare.MarkdownViewer.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\props\Base.props"/>
<Import Project="..\..\build\props\OneWare.Module.props"/>

<ItemGroup>
<ProjectReference Include="..\OneWare.Core\OneWare.Core.csproj"/>
</ItemGroup>
</Project>

128 changes: 128 additions & 0 deletions src/OneWare.MarkdownViewer/ViewModels/MarkdownEditViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using OneWare.Core.Services;
using OneWare.Core.ViewModels.DockViews;
using OneWare.Essentials.LanguageService;
using OneWare.Essentials.Models;
using OneWare.Essentials.Services;

namespace OneWare.MarkdownViewer.ViewModels;

/// <summary>
/// An <see cref="EditViewModel" /> for markdown files that adds a live preview pane.
/// The editor and the preview can be toggled independently to allow editor-only,
/// preview-only or split-screen layouts.
/// </summary>
public class MarkdownEditViewModel : EditViewModel
{
private readonly CompositeDisposable _markdownComposite = new();

private bool _showEditor = true;
private bool _showPreview = true;
private string? _markdownText;

public MarkdownEditViewModel(string fullPath, ILogger logger, IFileIconService fileIconService,
ISettingsService settingsService, IMainDockService mainDockService, ILanguageManager languageManager,
IWindowService windowService, IProjectExplorerService projectExplorerService, IErrorService errorService,
BackupService backupService) : base(fullPath, logger, fileIconService, settingsService, mainDockService,
languageManager, windowService, projectExplorerService, errorService, backupService)
{
ToggleEditorCommand = new RelayCommand(() => ShowEditor = !ShowEditor);
TogglePreviewCommand = new RelayCommand(() => ShowPreview = !ShowPreview);

// Keep the preview in sync with the editor content. The document instance can be
// replaced when the file is (re)loaded, so we listen to both events.
Editor.DocumentChanged += OnEditorChanged;

Observable.FromEventPattern(
h => Editor.TextChanged += h,
h => Editor.TextChanged -= h)
.Throttle(TimeSpan.FromMilliseconds(250))
.Subscribe(_ => UpdateMarkdown())
.DisposeWith(_markdownComposite);
}

public RelayCommand ToggleEditorCommand { get; }

public RelayCommand TogglePreviewCommand { get; }

public string? MarkdownText
{
get => _markdownText;
private set => SetProperty(ref _markdownText, value);
}

public bool ShowEditor
{
get => _showEditor;
set
{
// Always keep at least one pane visible.
if (!value && !ShowPreview) ShowPreview = true;
if (SetProperty(ref _showEditor, value))
{
OnPropertyChanged(nameof(IsSplitterVisible));
OnPropertyChanged(nameof(EditorColumnWidth));
}
}
}

public bool ShowPreview
{
get => _showPreview;
set
{
// Always keep at least one pane visible.
if (!value && !ShowEditor) ShowEditor = true;
if (SetProperty(ref _showPreview, value))
{
OnPropertyChanged(nameof(IsSplitterVisible));
OnPropertyChanged(nameof(PreviewColumnWidth));
if (value) UpdateMarkdown();
}
}
}

public bool IsSplitterVisible => ShowEditor && ShowPreview;

/// <summary>Star width when the editor is visible, collapsed otherwise.</summary>
public GridLength EditorColumnWidth =>
ShowEditor ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Auto);

/// <summary>Star width when the preview is visible, collapsed otherwise.</summary>
public GridLength PreviewColumnWidth =>
ShowPreview ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Auto);

private void OnEditorChanged(object? sender, EventArgs e)
{
UpdateMarkdown();
}

private void UpdateMarkdown()
{
if (Dispatcher.UIThread.CheckAccess())
MarkdownText = Editor.Document?.Text ?? string.Empty;
else
Dispatcher.UIThread.Post(() => MarkdownText = Editor.Document?.Text ?? string.Empty);
}

public override bool OnClose()
{
var result = base.OnClose();
if (!result) return false;

Editor.DocumentChanged -= OnEditorChanged;
_markdownComposite.Dispose();
return true;
}
}






58 changes: 58 additions & 0 deletions src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:OneWare.MarkdownViewer.ViewModels"
xmlns:controls="clr-namespace:OneWare.Essentials.Controls;assembly=OneWare.Essentials"
xmlns:dockViews="clr-namespace:OneWare.Core.Views.DockViews;assembly=OneWare.Core"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="OneWare.MarkdownViewer.Views.MarkdownEditView"
x:DataType="viewModels:MarkdownEditViewModel"
Background="{DynamicResource ThemeControlLowBrush}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding EditorColumnWidth}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{Binding PreviewColumnWidth}" />
</Grid.ColumnDefinitions>
<!-- Reuse the standard editor for full editing support -->
<dockViews:EditView Grid.Column="0" IsVisible="{Binding ShowEditor}" />

<GridSplitter Grid.Column="1" Width="4" ResizeDirection="Columns"
Background="{DynamicResource ThemeBorderLowBrush}"
IsVisible="{Binding IsSplitterVisible}" />

<controls:MarkdownViewer Grid.Column="2"
IsVisible="{Binding ShowPreview}"
SelectionEnabled="True"
Margin="8,4"
Markdown="{Binding MarkdownText}" />

<!-- Floating toggle buttons in the top-right corner, overlaying all columns -->
<Border Grid.Column="0" Grid.ColumnSpan="3"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,8,30,0"
Background="{DynamicResource ThemeBackgroundBrush}"
BorderBrush="{DynamicResource ThemeBorderLowBrush}"
BorderThickness="1" CornerRadius="3"
Padding="2" BoxShadow="0 1 4 0 #20000000">
<StackPanel Orientation="Horizontal" Spacing="2">
<ToggleButton IsChecked="{Binding ShowEditor, Mode=TwoWay}"
ToolTip.Tip="Toggle editor"
Padding="4" Width="20" Height="20">
<Image Width="12" Height="12"
Source="{DynamicResource Cool.Edit}" />
</ToggleButton>
<ToggleButton IsChecked="{Binding ShowPreview, Mode=TwoWay}"
ToolTip.Tip="Toggle preview"
Padding="4" Width="20" Height="20">
<Image Width="12" Height="12"
Source="{DynamicResource FontAwesome.EyeSolid}" />
</ToggleButton>
</StackPanel>
</Border>
</Grid>
</UserControl>



12 changes: 12 additions & 0 deletions src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Avalonia.Controls;

namespace OneWare.MarkdownViewer.Views;

public partial class MarkdownEditView : UserControl
{
public MarkdownEditView()
{
InitializeComponent();
}
}

1 change: 1 addition & 0 deletions studio/OneWare.Studio/OneWare.Studio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ProjectReference Include="..\..\src\OneWare.Core\OneWare.Core.csproj"/>
<ProjectReference Include="..\..\src\OneWare.Cpp\OneWare.Cpp.csproj"/>
<ProjectReference Include="..\..\src\OneWare.CruviAdapterExtensions\OneWare.CruviAdapterExtensions.csproj"/>
<ProjectReference Include="..\..\src\OneWare.MarkdownViewer\OneWare.MarkdownViewer.csproj"/>
<ProjectReference Include="..\..\src\OneWare.UniversalFpgaProjectSystem\OneWare.UniversalFpgaProjectSystem.csproj"/>
<ProjectReference Include="..\..\src\OneWare.Vcd.Viewer\OneWare.Vcd.Viewer.csproj"/>
</ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions studio/OneWare.Studio/StudioApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using OneWare.CruviAdapterExtensions;
using OneWare.Essentials.Models;
using OneWare.Essentials.Services;
using OneWare.MarkdownViewer;
using OneWare.Settings;
using OneWare.Studio.Styles;
using OneWare.UniversalFpgaProjectSystem;
Expand Down Expand Up @@ -98,5 +99,6 @@ protected override void ConfigureModuleCatalog(OneWareModuleCatalog moduleCatalo
moduleCatalog.AddModule<UniversalFpgaProjectSystemModule>();
moduleCatalog.AddModule<VcdViewerModule>();
moduleCatalog.AddModule<CruviAdapterExtensionsModule>();
moduleCatalog.AddModule<MarkdownViewerModule>();
}
}
Loading