Skip to content

Commit

Permalink
Merge pull request #21 from one-ware/libraries
Browse files Browse the repository at this point in the history
Add Library Explorer
  • Loading branch information
HendrikMennen authored Oct 22, 2024
2 parents b493a04 + 20b763b commit 811c4ec
Show file tree
Hide file tree
Showing 15 changed files with 441 additions and 40 deletions.
7 changes: 7 additions & 0 deletions OneWare.sln
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneWare.UniversalFpgaProjec
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneWare.CruviAdapterExtensions", "src\OneWare.CruviAdapterExtensions\OneWare.CruviAdapterExtensions.csproj", "{01BC6288-6AD8-4D70-9360-F84601CCBA56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneWare.LibraryExplorer", "src\OneWare.LibraryExplorer\OneWare.LibraryExplorer.csproj", "{2E44F2EC-6C27-4E44-8F03-E6D95C9B8B34}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -360,6 +362,10 @@ Global
{01BC6288-6AD8-4D70-9360-F84601CCBA56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01BC6288-6AD8-4D70-9360-F84601CCBA56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01BC6288-6AD8-4D70-9360-F84601CCBA56}.Release|Any CPU.Build.0 = Release|Any CPU
{2E44F2EC-6C27-4E44-8F03-E6D95C9B8B34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E44F2EC-6C27-4E44-8F03-E6D95C9B8B34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E44F2EC-6C27-4E44-8F03-E6D95C9B8B34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E44F2EC-6C27-4E44-8F03-E6D95C9B8B34}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F08B36E8-AB80-42CD-BD47-6B05E96DA390} = {0761690C-7DA0-4554-9F6B-211088412DCD}
Expand Down Expand Up @@ -416,5 +422,6 @@ Global
{AAC4D6FA-4F94-4616-93B3-3BB47E4A0BB1} = {EB783E04-C3C8-45F8-B810-24798DAE2450}
{484F3E48-EF14-4801-B896-41BDB67A54E6} = {EB783E04-C3C8-45F8-B810-24798DAE2450}
{01BC6288-6AD8-4D70-9360-F84601CCBA56} = {53C7F88A-3B98-4AB4-992B-71C1F91F1BA7}
{2E44F2EC-6C27-4E44-8F03-E6D95C9B8B34} = {0761690C-7DA0-4554-9F6B-211088412DCD}
EndGlobalSection
EndGlobal
2 changes: 2 additions & 0 deletions src/OneWare.Core/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using OneWare.FolderProjectSystem;
using OneWare.ImageViewer;
using OneWare.Json;
using OneWare.LibraryExplorer;
using OneWare.Output;
using OneWare.ProjectExplorer;
using OneWare.ProjectSystem.Services;
Expand Down Expand Up @@ -300,6 +301,7 @@ protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
moduleCatalog.AddModule<ErrorListModule>();
moduleCatalog.AddModule<OutputModule>();
moduleCatalog.AddModule<ProjectExplorerModule>();
moduleCatalog.AddModule<LibraryExplorerModule>();
moduleCatalog.AddModule<FolderProjectSystemModule>();
moduleCatalog.AddModule<ImageViewerModule>();
moduleCatalog.AddModule<JsonModule>();
Expand Down
1 change: 1 addition & 0 deletions src/OneWare.Core/OneWare.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<ProjectReference Include="..\OneWare.FolderProjectSystem\OneWare.FolderProjectSystem.csproj"/>
<ProjectReference Include="..\OneWare.ImageViewer\OneWare.ImageViewer.csproj"/>
<ProjectReference Include="..\OneWare.Json\OneWare.Json.csproj"/>
<ProjectReference Include="..\OneWare.LibraryExplorer\OneWare.LibraryExplorer.csproj" />
<ProjectReference Include="..\OneWare.Output\OneWare.Output.csproj"/>
<ProjectReference Include="..\OneWare.ProjectExplorer\OneWare.ProjectExplorer.csproj"/>
<ProjectReference Include="..\OneWare.ProjectSystem\OneWare.ProjectSystem.csproj"/>
Expand Down
3 changes: 1 addition & 2 deletions src/OneWare.Core/ViewModels/DockViews/EditViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public class EditViewModel : ExtendedDocument, IEditor
private readonly IWindowService _windowService;

private CompositeDisposable _composite = new();



private IEnumerable<ErrorListItem>? _diagnostics;

private ITypeAssistance? _typeAssistance;
Expand Down
1 change: 1 addition & 0 deletions src/OneWare.Core/Views/DockViews/EditView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
<Setter Property="ShowLineNumbers" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource ThemeEditorBrush}" />
<Setter Property="VerticalScrollBarVisibility" Value="Visible" />
<Setter Property="IsReadOnly" Value="{Binding IsReadOnly}"/>
</Style>
</ContentControl.Styles>
</ContentControl>
Expand Down
1 change: 1 addition & 0 deletions src/OneWare.Essentials/Services/IProjectExplorerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public Task<IProjectRoot?>
public Task<IProjectEntry> RenameAsync(IProjectEntry entry, string newName);
public void ExpandToRoot(IProjectExplorerNode node);
public Task ImportFolderDialogAsync(IProjectFolder? destination = null);
public Task ImportAsync(IProjectFolder destination, bool copy, bool askForInclude, params string[] paths);
public Task<IProjectEntry> ReloadAsync(IProjectEntry entry);
public Task SaveProjectAsync(IProjectRoot project);
public Task SaveLastProjectsFileAsync();
Expand Down
37 changes: 37 additions & 0 deletions src/OneWare.LibraryExplorer/LibraryExplorerModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Avalonia;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.Input;
using OneWare.Essentials.Enums;
using OneWare.Essentials.Services;
using OneWare.Essentials.ViewModels;
using OneWare.LibraryExplorer.ViewModels;
using OneWare.ProjectExplorer.ViewModels;
using Prism.Ioc;
using Prism.Modularity;

namespace OneWare.LibraryExplorer;

public class LibraryExplorerModule : IModule
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<LibraryExplorerViewModel>();
}

public void OnInitialized(IContainerProvider containerProvider)
{
var dockService = containerProvider.Resolve<IDockService>();
var windowService = containerProvider.Resolve<IWindowService>();

dockService.RegisterLayoutExtension<LibraryExplorerViewModel>(DockShowLocation.Left);

windowService.RegisterMenuItem("MainWindow_MainMenu/View/Tool Windows",
new MenuItemViewModel("Library Explorer")
{
Header = "Library Explorer",
Command =
new RelayCommand(() => dockService.Show(containerProvider.Resolve<LibraryExplorerViewModel>())),
IconObservable = Application.Current!.GetResourceObservable(LibraryExplorerViewModel.IconKey)
});
}
}
17 changes: 17 additions & 0 deletions src/OneWare.LibraryExplorer/OneWare.LibraryExplorer.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\props\Base.props"/>
<Import Project="..\..\build\props\OneWare.Module.props"/>

<ItemGroup>
<ProjectReference Include="..\OneWare.Essentials\OneWare.Essentials.csproj"/>
<ProjectReference Include="..\OneWare.FolderProjectSystem\OneWare.FolderProjectSystem.csproj" />
<ProjectReference Include="..\OneWare.ProjectExplorer\OneWare.ProjectExplorer.csproj"/>
</ItemGroup>

<ItemGroup>
<Compile Update="Views\LibraryExplorerView.axaml.cs">
<DependentUpon>ProjectExplorerView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project>
133 changes: 133 additions & 0 deletions src/OneWare.LibraryExplorer/ViewModels/LibraryExplorerViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using Avalonia;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.Input;
using Dock.Model.Core;
using OneWare.Essentials.Helpers;
using OneWare.Essentials.Models;
using OneWare.Essentials.Services;
using OneWare.Essentials.ViewModels;
using OneWare.FolderProjectSystem;
using OneWare.ProjectExplorer.Services;
using OneWare.ProjectExplorer.ViewModels;
using Prism.Ioc;

namespace OneWare.LibraryExplorer.ViewModels;

public class LibraryExplorerViewModel : ProjectViewModelBase
{
public const string IconKey = "BoxIcons.RegularLibrary";

private string _libraryFolderPath;

private readonly IFileWatchService _fileWatchService;
private readonly IDockService _dockService;
private readonly IProjectExplorerService _projectExplorerService;

public LibraryExplorerViewModel(IPaths paths, IFileWatchService fileWatchService, IDockService dockService, IProjectExplorerService projectExplorerService) : base(IconKey)
{
Id = "LibraryExplorer";
Title = "Library Explorer";

_fileWatchService = fileWatchService;
_dockService = dockService;
_projectExplorerService = projectExplorerService;

_libraryFolderPath = Path.Combine(paths.PackagesDirectory, "Libraries");

_ = LoadAsync();
}

public override void Insert(IProjectRoot project)
{
base.Insert(project);
_fileWatchService.Register(project);
}

public void DoubleTab(IProjectEntry entry)
{
if (entry is IProjectFile file)
_ = PreviewFileAsync(file);
else
entry.IsExpanded = !entry.IsExpanded;
}

public async Task LoadAsync()
{
var manager = ContainerLocator.Container.Resolve<FolderProjectManager>();

Directory.CreateDirectory(_libraryFolderPath);
var directories = Directory.EnumerateDirectories(_libraryFolderPath);

Projects.Clear();

foreach (var dir in directories)
{
var root = await manager.LoadProjectAsync(dir);
Insert(root!);
}
}

public void ConstructContextMenu(TopLevel topLevel)
{
var menuItems = new List<MenuItemViewModel>();

if (SelectedItems is [{ } item])
{
switch (item)
{
case IProjectFile file:
menuItems.Add(new MenuItemViewModel("Open")
{
Header = "Open",
Command = new AsyncRelayCommand(() => PreviewFileAsync(file))
});
break;
}
}
if (SelectedItems.Count > 0)
{
menuItems.Add(new MenuItemViewModel("Copy to Project")
{
Header = "Copy to Active Project",
Command = new AsyncRelayCommand(() => CopyLibraryAsync(SelectedItems.Cast<IProjectEntry>()
.ToArray()), () => _projectExplorerService.ActiveProject != null)
});
}
else
{
menuItems.Add(new MenuItemViewModel("Refresh")
{
Header = "Refresh",
Command = new RelayCommand(() => PlatformHelper.OpenExplorerPath(_libraryFolderPath))
});
menuItems.Add(new MenuItemViewModel("Open Library Folder")
{
Header = "Open Library Folder",
Command = new RelayCommand(() => PlatformHelper.OpenExplorerPath(_libraryFolderPath))
});
}

TreeViewContextMenu = menuItems;
}

private async Task PreviewFileAsync(IProjectFile file)
{
var extendedDocument = await _dockService.OpenFileAsync(file);
if (extendedDocument != null)
{
extendedDocument.IsReadOnly = true;
extendedDocument.Title = "PREVIEW: " + extendedDocument.CurrentFile?.Name;
}
}

private async Task CopyLibraryAsync(params IProjectEntry[] entries)
{
var proj = _projectExplorerService.ActiveProject;

if(proj == null) return;

var libFolder = proj.AddFolder("lib");

await _projectExplorerService.ImportAsync(libFolder, true, true, entries.Select(x => x.FullPath).ToArray());
}
}
123 changes: 123 additions & 0 deletions src/OneWare.LibraryExplorer/Views/LibraryExplorerView.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<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:controls="clr-namespace:OneWare.Essentials.Controls;assembly=OneWare.Essentials"
xmlns:models="clr-namespace:OneWare.Essentials.Models;assembly=OneWare.Essentials"
xmlns:behaviors="clr-namespace:OneWare.Essentials.Behaviors;assembly=OneWare.Essentials"
xmlns:behaviors1="clr-namespace:OneWare.ProjectExplorer.Behaviors"
xmlns:viewModels="clr-namespace:OneWare.LibraryExplorer.ViewModels"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450"
x:Class="OneWare.LibraryExplorer.Views.LibraryExplorerView"
Background="{DynamicResource ThemeControlLowBrush}"
BorderBrush="{DynamicResource ThemeBorderLowBrush}"
x:CompileBindings="True" x:DataType="viewModels:LibraryExplorerViewModel"
Name="ProjectExplorerViewView"
Foreground="{DynamicResource ThemeForegroundColor}"
BorderThickness="0">

<UserControl.Styles>

<Style Selector="TextBox">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="TextWrapping" Value="NoWrap" />
</Style>

</UserControl.Styles>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" BorderBrush="{DynamicResource ThemeBorderLowBrush}" BorderThickness="0 1 0 1">
<controls:SearchBox Background="{DynamicResource ThemeBackgroundBrush}"
SearchText="{Binding SearchString, Mode=TwoWay}" VerticalAlignment="Center"
VerticalContentAlignment="Center" x:Name="SearchBox" Height="24" />
</Border>
<TreeView AutoScrollToSelectedItem="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" SelectionMode="Multiple"
SelectedItems="{Binding SelectedItems, Mode=TwoWay}" Grid.Row="1" Name="ProjectTree"
ItemsSource="{Binding Projects}">
<TreeView.ContextMenu>
<ContextMenu Classes="BindMenu" x:Name="TreeViewContextMenu"
ItemsSource="{Binding TreeViewContextMenu}" />
</TreeView.ContextMenu>
<TreeView.Styles>
<Style Selector="TreeViewItem" x:DataType="models:IProjectExplorerNode">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<Setter Property="Background" Value="{Binding Background}" />
</Style>
</TreeView.Styles>
<TreeView.DataTemplates>
<TreeDataTemplate DataType="models:IProjectExplorerNode" ItemsSource="{Binding Children}">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
<ItemsControl ItemsSource="{Binding RightIcons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="3" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding }" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>

<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" Spacing="4" Background="Transparent">
<Interaction.Behaviors>
<behaviors:CommandOnDoubleTapBehavior
Command="{Binding $parent[TreeView].((viewModels:LibraryExplorerViewModel)DataContext).DoubleTab, FallbackValue={x:Null}}"
CommandParameter="{Binding}" />
</Interaction.Behaviors>

<Grid VerticalAlignment="Center">
<Image Height="16" Width="16"
Source="{Binding Icon}" />
<ItemsControl ItemsSource="{Binding IconOverlays}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Panel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding }" Height="16" Width="16" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>

<!--
<Grid DockPanel.Dock="Right" Width="11">
<TextBlock HorizontalAlignment="Center"
ToolTip.Tip="{Binding GitChangeStatus, Converter={StaticResource EnumToStringConverter}}"
Text="{Binding GitChangeStatus, Converter={StaticResource ChangeStatusCharConverter}}"
FontWeight="Bold"
Foreground="{Binding GitChangeStatus, Converter={StaticResource ChangeStatusBrushConverter}}" />
</Grid>-->

<controls:RenamingTextBox FontWeight="{Binding FontWeight}" ToolTip.Tip="{Binding Header}"
VerticalAlignment="Center"
IsEnabled="False" x:Name="RenamingTextBox"
Text="{Binding Header, Mode=OneWay}"
RenameAction="{Binding (models:IProjectEntry).RequestRename}"
Opacity="{Binding TextOpacity}" />
</StackPanel>
</DockPanel>
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
</Grid>


</UserControl>
Loading

0 comments on commit 811c4ec

Please sign in to comment.