fix: extra space of MenuItem

see: https://github.com/AvaloniaUI/Avalonia/issues/6905
This commit is contained in:
walterlv 2024-04-08 18:00:58 +08:00
parent 0426e24c6e
commit fdff62e317
3 changed files with 32 additions and 91 deletions

View file

@ -95,15 +95,15 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _selectedView, value); set => SetProperty(ref _selectedView, value);
} }
public AvaloniaList<ExternalMenuItem> ExternalTerminals public AvaloniaList<MenuItem> ExternalTerminals
{ {
get; get;
} = new AvaloniaList<ExternalMenuItem>(); } = [];
public AvaloniaList<ExternalMenuItem> ExternalEditors public AvaloniaList<MenuItem> ExternalEditors
{ {
get; get;
} = new AvaloniaList<ExternalMenuItem>(); } = [];
[JsonIgnore] [JsonIgnore]
public List<Models.Remote> Remotes public List<Models.Remote> Remotes
@ -330,52 +330,66 @@ namespace SourceGit.ViewModels
} }
} }
public ImmutableArray<ExternalMenuItem> CreateContextMenuForExternalTerminals() public ImmutableArray<MenuItem> CreateContextMenuForExternalTerminals()
{ {
var terminals = Native.OS.ExternalTerminals; var terminals = Native.OS.ExternalTerminals;
if (terminals.Count == 0) if (terminals.Count == 0)
{ {
App.RaiseException(_fullpath, "No available external terminals found!"); App.RaiseException(_fullpath, "No available external terminals found!");
return [new ExternalMenuItem("No terminal found") return [new MenuItem
{ {
Header = "No terminal found",
IsEnabled = false, IsEnabled = false,
}]; }];
} }
var items = new List<ExternalMenuItem>(terminals.Count); var items = new List<MenuItem>(terminals.Count);
foreach (var terminal in terminals) foreach (var terminal in terminals)
{ {
var dupTerminal = terminal; var dupTerminal = terminal;
var item = new ExternalMenuItem( var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/ExternalTerminalIcons/{dupTerminal.Icon}", UriKind.RelativeOrAbsolute));
App.Text("Repository.OpenIn", dupTerminal.Name), var item = new MenuItem
$"ExternalTerminalIcons/{dupTerminal.Icon}", {
() => dupTerminal.Open(_fullpath)); Header = App.Text("Repository.OpenIn", dupTerminal.Name),
Icon = new Image
{
Width = 16, Height = 16, Source = new Bitmap(icon),
},
Command = new RelayCommand(() => dupTerminal.Open(_fullpath)),
};
items.Add(item); items.Add(item);
} }
return [..items]; return [..items];
} }
public ImmutableArray<ExternalMenuItem> CreateContextMenuForExternalEditors() public ImmutableArray<MenuItem> CreateContextMenuForExternalEditors()
{ {
var editors = Native.OS.ExternalEditors; var editors = Native.OS.ExternalEditors;
if (editors.Count == 0) if (editors.Count == 0)
{ {
App.RaiseException(_fullpath, "No available external editors found!"); App.RaiseException(_fullpath, "No available external editors found!");
return [new ExternalMenuItem("No editor found") return [new MenuItem
{ {
Header = "No editor found",
IsEnabled = false, IsEnabled = false,
}]; }];
} }
var items = new List<ExternalMenuItem>(editors.Count); var items = new List<MenuItem>(editors.Count);
foreach (var editor in editors) foreach (var editor in editors)
{ {
var dupEditor = editor; var dupEditor = editor;
var item = new ExternalMenuItem( var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/ExternalToolIcons/{dupEditor.Icon}", UriKind.RelativeOrAbsolute));
App.Text("Repository.OpenIn", dupEditor.Name), var item = new MenuItem
$"ExternalToolIcons/{dupEditor.Icon}", {
() => dupEditor.Open(_fullpath)); Header = App.Text("Repository.OpenIn", dupEditor.Name),
Icon = new Image
{
Width = 16, Height = 16, Source = new Bitmap(icon),
},
Command = new RelayCommand(() => dupEditor.Open(_fullpath)),
};
items.Add(item); items.Add(item);
} }
@ -1419,44 +1433,4 @@ namespace SourceGit.ViewModels
private InProgressContext _inProgressContext = null; private InProgressContext _inProgressContext = null;
private bool _hasUnsolvedConflicts = false; private bool _hasUnsolvedConflicts = false;
} }
/// <summary>
/// A menu item for external tools.
/// </summary>
public readonly record struct ExternalMenuItem
{
public ExternalMenuItem(string header)
{
Header = header;
IconKey = null;
Command = null;
}
public ExternalMenuItem(string header, string iconKey, Action click)
{
Header = header;
IconKey = iconKey;
Command = new RelayCommand(click);
}
/// <summary>
/// The external tool name.
/// </summary>
public string Header { get; }
/// <summary>
/// The resource key of the icon.
/// </summary>
public string? IconKey { get; init; }
/// <summary>
/// The command when the user click the menu item.
/// </summary>
public ICommand Command { get; }
/// <summary>
/// <see langword="true"/> if the menu item is enabled; otherwise, <see langword="false"/>.
/// </summary>
public bool IsEnabled { get; init; } = true;
}
} }

View file

@ -11,23 +11,12 @@
x:DataType="vm:Repository"> x:DataType="vm:Repository">
<UserControl.Resources> <UserControl.Resources>
<v:ExternalIconKeyToImageConverter x:Key="IconKeyToImageConverter" />
<MenuFlyout x:Key="TerminalShellsMenuFlyout" Placement="BottomEdgeAlignedLeft" <MenuFlyout x:Key="TerminalShellsMenuFlyout" Placement="BottomEdgeAlignedLeft"
ItemsSource="{Binding ExternalTerminals, Mode=OneTime}" /> ItemsSource="{Binding ExternalTerminals, Mode=OneTime}" />
<MenuFlyout x:Key="ExternalToolsMenuFlyout" Placement="BottomEdgeAlignedLeft" <MenuFlyout x:Key="ExternalToolsMenuFlyout" Placement="BottomEdgeAlignedLeft"
ItemsSource="{Binding ExternalEditors, Mode=OneTime}" /> ItemsSource="{Binding ExternalEditors, Mode=OneTime}" />
</UserControl.Resources> </UserControl.Resources>
<UserControl.DataTemplates>
<DataTemplate x:DataType="vm:ExternalMenuItem">
<MenuItem Header="{Binding Header, Mode=OneTime}"
Icon="{Binding IconKey, Mode=OneTime, Converter={StaticResource IconKeyToImageConverter}}"
Command="{Binding Command, Mode=OneTime}"
IsEnabled="{Binding IsEnabled, Mode=OneTime}">
</MenuItem>
</DataTemplate>
</UserControl.DataTemplates>
<Grid RowDefinitions="36,*" Background="{DynamicResource Brush.Window}"> <Grid RowDefinitions="36,*" Background="{DynamicResource Brush.Window}">
<!-- Toolbar --> <!-- Toolbar -->
<Border Grid.Row="0" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" Background="{DynamicResource Brush.ToolBar}"> <Border Grid.Row="0" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" Background="{DynamicResource Brush.ToolBar}">

View file

@ -305,26 +305,4 @@ namespace SourceGit.Views
} }
} }
} }
public sealed class ExternalIconKeyToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string iconKey && !string.IsNullOrWhiteSpace(iconKey))
{
var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/{iconKey}", UriKind.RelativeOrAbsolute));
return new Image
{
Width = 16, Height = 16, Source = new Bitmap(icon),
};
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
} }