diff --git a/Source/LibationAvalonia/Assets/LibationStyles.xaml b/Source/LibationAvalonia/Assets/LibationStyles.xaml index 02ab0277..7b3ae474 100644 --- a/Source/LibationAvalonia/Assets/LibationStyles.xaml +++ b/Source/LibationAvalonia/Assets/LibationStyles.xaml @@ -1,8 +1,8 @@ - #FFE6FFE6 + #cdffcd - + diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml new file mode 100644 index 00000000..69d12455 --- /dev/null +++ b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml @@ -0,0 +1,7 @@ + + + diff --git a/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs new file mode 100644 index 00000000..b46fac89 --- /dev/null +++ b/Source/LibationAvalonia/Controls/DataGridTemplateColumnExt.axaml.cs @@ -0,0 +1,73 @@ +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using LibationAvalonia.ViewModels; +using System; +using System.Reflection; + +namespace LibationAvalonia.Controls +{ + public class DataGridCellContextMenuStripNeededEventArgs + { + private static readonly MethodInfo GetCellValueMethod; + static DataGridCellContextMenuStripNeededEventArgs() + { + GetCellValueMethod = typeof(DataGridColumn).GetMethod("GetCellValue", BindingFlags.NonPublic | BindingFlags.Instance); + } + + private static string GetCellValue(DataGridColumn column, object item) + => GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? ""; + + public string CellClipboardContents => GetCellValue(Column, GridEntry); + public DataGridTemplateColumnExt Column { get; init; } + public GridEntry GridEntry { get; init; } + public ContextMenu ContextMenu { get; init; } + public AvaloniaList ContextMenuItems + => ContextMenu.Items as AvaloniaList; + } + + public partial class DataGridTemplateColumnExt : DataGridTemplateColumn + { + public event EventHandler CellContextMenuStripNeeded; + + private static readonly ContextMenu ContextMenu = new(); + private static readonly AvaloniaList MenuItems = new(); + + public DataGridTemplateColumnExt() + { + AvaloniaXamlLoader.Load(this); + ContextMenu.Items = MenuItems; + } + + private void Cell_ContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGridCell cell && cell.DataContext is GridEntry entry) + { + var args = new DataGridCellContextMenuStripNeededEventArgs + { + Column = this, + GridEntry = entry, + ContextMenu = ContextMenu + }; + args.ContextMenuItems.Clear(); + + CellContextMenuStripNeeded?.Invoke(sender, args); + + e.Handled = args.ContextMenuItems.Count == 0; + } + else + e.Handled = true; + } + + protected override IControl GenerateElement(DataGridCell cell, object dataItem) + { + if (cell.ContextMenu is null) + { + cell.ContextRequested += Cell_ContextRequested; + cell.ContextMenu = ContextMenu; + } + + return base.GenerateElement(cell, dataItem); + } + } +} diff --git a/Source/LibationAvalonia/ViewModels/GridEntry.cs b/Source/LibationAvalonia/ViewModels/GridEntry.cs index 4f055750..ec30d49f 100644 --- a/Source/LibationAvalonia/ViewModels/GridEntry.cs +++ b/Source/LibationAvalonia/ViewModels/GridEntry.cs @@ -51,7 +51,8 @@ namespace LibationAvalonia.ViewModels public abstract bool IsSeries { get; } public abstract bool IsEpisode { get; } public abstract bool IsBook { get; } - public IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : null; + public abstract double Opacity { get; } + public IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : Brushes.Transparent; #endregion diff --git a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs index 54dc7fb8..5a2423e7 100644 --- a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs +++ b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs @@ -53,6 +53,7 @@ namespace LibationAvalonia.ViewModels public override bool IsSeries => false; public override bool IsEpisode => Parent is not null; public override bool IsBook => Parent is null; + public override double Opacity => Book.UserDefinedItem.Tags.ToLower().Contains("hidden") ? 0.4 : 1; #endregion @@ -99,6 +100,7 @@ namespace LibationAvalonia.ViewModels case nameof(udi.Tags): Book.UserDefinedItem.Tags = udi.Tags; this.RaisePropertyChanged(nameof(BookTags)); + this.RaisePropertyChanged(nameof(Opacity)); break; case nameof(udi.BookStatus): Book.UserDefinedItem.BookStatus = udi.BookStatus; diff --git a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs index bd457171..eb82a99b 100644 --- a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs +++ b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs @@ -50,6 +50,7 @@ namespace LibationAvalonia.ViewModels public override bool IsSeries => true; public override bool IsEpisode => false; public override bool IsBook => false; + public override double Opacity => 1; #endregion diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index 1371b44a..a4a7fbae 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -15,11 +15,24 @@ GridLinesVisibility="All" AutoGenerateColumns="False" Items="{Binding GridEntries}" - CanUserSortColumns="True" + CanUserSortColumns="True" BorderThickness="3" CanUserReorderColumns="True"> + + + + + - + - + - + - - + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - - + + - + - + - - - + - + diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs index bd4e7fae..ac57d42b 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs @@ -10,7 +10,7 @@ using LibationAvalonia.Dialogs; using System; using System.Collections.Generic; using System.Linq; -using Avalonia.Interactivity; +using LibationAvalonia.Controls; namespace LibationAvalonia.Views { @@ -53,7 +53,7 @@ namespace LibationAvalonia.Views { column.CustomSortComparer = new RowComparer(column); } - } + } private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) { @@ -71,6 +71,29 @@ namespace LibationAvalonia.Views productsGrid = this.FindControl(nameof(productsGrid)); } + #region Cell Context Menu + + public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args) + { + if (args.Column.SortMemberPath == "Liberate") + { + + } + else + { + // any non-stop light column + // (except for the Cover column which does not have a context menu) + var menuItem = new MenuItem { Header = "_Copy Cell Contents" }; + + menuItem.Click += async (s, e) + => await Application.Current.Clipboard.SetTextAsync(args.CellClipboardContents); + + args.ContextMenuItems.Add(menuItem); + } + } + + #endregion + #region Column Customizations private void Configure_ColumnCustomization() @@ -96,6 +119,10 @@ namespace LibationAvalonia.Views foreach (var column in productsGrid.Columns) { + //Wire up column context menu + if (column is DataGridTemplateColumnExt tc) + tc.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded; + var itemName = column.SortMemberPath; if (itemName == nameof(GridEntry.Remove)) @@ -185,22 +212,6 @@ namespace LibationAvalonia.Views #region Button Click Handlers - public void ContextMenuItem1_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) - { - var lbe = getBoundEntry(args.Source); - } - public void ContextMenuItem2_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) - { - var lbe = getBoundEntry(args.Source); - } - public void ContextMenuItem3_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) - { - var lbe = getBoundEntry(args.Source); - } - - private static LibraryBookEntry getBoundEntry(IInteractive source) - => (source is IStyledElement se && se.DataContext is LibraryBookEntry lbe ? lbe : null); - public void LiberateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) { var button = args.Source as Button; @@ -266,9 +277,9 @@ namespace LibationAvalonia.Views public void Description_Click(object sender, Avalonia.Input.TappedEventArgs args) { - if (sender is TextBlock tblock && tblock.DataContext is GridEntry gEntry) + if (sender is Control tblock && tblock.DataContext is GridEntry gEntry) { - var pt = tblock.Parent.PointToScreen(tblock.Parent.Bounds.TopRight); + var pt = tblock.PointToScreen(tblock.Bounds.TopRight); var displayWindow = new DescriptionDisplayDialog { SpawnLocation = new Point(pt.X, pt.Y),