mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-10-31 13:03:20 -07:00
refactor: custom renderer for launcher tab bar
This commit is contained in:
parent
bfea573d4b
commit
1241539260
6 changed files with 112 additions and 47 deletions
|
@ -627,10 +627,6 @@
|
|||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.launcher_pagetab">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
</Style>
|
||||
<Style Selector="ListBox.launcher_page_tabbar">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
|
@ -642,15 +638,13 @@
|
|||
<Setter Property="Opacity" Value=".5"/>
|
||||
</Style>
|
||||
<Style Selector="ListBox.launcher_page_tabbar ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Opacity" Value=".85"/>
|
||||
</Style>
|
||||
<Style Selector="ListBox.launcher_page_tabbar ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Opacity" Value="1"/>
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:selected Border.launcher_pagetab">
|
||||
<Setter Property="Background" Value="{DynamicResource Brush.ToolBar}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="ContextMenu">
|
||||
<Setter Property="HorizontalOffset" Value="-4"/>
|
||||
|
|
|
@ -24,10 +24,7 @@ namespace SourceGit.ViewModels
|
|||
set
|
||||
{
|
||||
if (SetProperty(ref _activePage, value))
|
||||
{
|
||||
PopupHost.Active = value;
|
||||
UpdateTabSplitterVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,9 +66,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var lastActiveIdx = Preference.Instance.LastActiveTabIdx;
|
||||
if (lastActiveIdx >= 0 && lastActiveIdx < Pages.Count)
|
||||
{
|
||||
ActivePage = Pages[lastActiveIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,13 +156,11 @@ namespace SourceGit.ViewModels
|
|||
ActivePage = Pages[removeIdx == Pages.Count - 1 ? removeIdx - 1 : removeIdx + 1];
|
||||
CloseRepositoryInTab(page);
|
||||
Pages.RemoveAt(removeIdx);
|
||||
UpdateTabSplitterVisible();
|
||||
}
|
||||
else if (removeIdx + 1 == activeIdx)
|
||||
{
|
||||
CloseRepositoryInTab(page);
|
||||
Pages.RemoveAt(removeIdx);
|
||||
UpdateTabSplitterVisible();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -365,13 +358,6 @@ namespace SourceGit.ViewModels
|
|||
page.Data = null;
|
||||
}
|
||||
|
||||
private void UpdateTabSplitterVisible()
|
||||
{
|
||||
var activePageIdx = ActivePage == null ? -1 : Pages.IndexOf(ActivePage);
|
||||
for (int i = 0; i < Pages.Count; i++)
|
||||
Pages[i].IsTabSplitterVisible = (activePageIdx != i && activePageIdx != i + 1);
|
||||
}
|
||||
|
||||
private LauncherPage _activePage = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,6 @@ namespace SourceGit.ViewModels
|
|||
set => SetProperty(ref _data, value);
|
||||
}
|
||||
|
||||
public bool IsTabSplitterVisible
|
||||
{
|
||||
get => _isTabSplitterVisible;
|
||||
set => SetProperty(ref _isTabSplitterVisible, value);
|
||||
}
|
||||
|
||||
public AvaloniaList<Notification> Notifications
|
||||
{
|
||||
get;
|
||||
|
@ -55,6 +49,5 @@ namespace SourceGit.ViewModels
|
|||
|
||||
private RepositoryNode _node = null;
|
||||
private object _data = null;
|
||||
private bool _isTabSplitterVisible = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,7 @@
|
|||
</Border>
|
||||
|
||||
<!-- Menu (Windows/Linux) -->
|
||||
<Button Grid.Column="0" Classes="icon_button" VerticalAlignment="Bottom" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<Button.Margin>
|
||||
<OnPlatform Default="4,0,2,3" macOS="4,0,6,3"/>
|
||||
</Button.Margin>
|
||||
|
||||
<Button Grid.Column="0" Classes="icon_button" VerticalAlignment="Bottom" Margin="6,0,2,3" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<Button.Flyout>
|
||||
<MenuFlyout Placement="BottomEdgeAlignedLeft" VerticalOffset="-8">
|
||||
<MenuItem Header="{DynamicResource Text.Preference}" Command="{x:Static s:App.OpenPreferenceCommand}" InputGesture="Ctrl+Shift+P">
|
||||
|
|
|
@ -15,17 +15,20 @@
|
|||
</RepeatButton>
|
||||
|
||||
<ScrollViewer Grid.Column="1"
|
||||
Margin="6,0"
|
||||
x:Name="LauncherTabsScroller"
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Disabled"
|
||||
PointerWheelChanged="ScrollTabs"
|
||||
LayoutUpdated="OnTabsLayoutUpdated">
|
||||
PointerWheelChanged="ScrollTabs">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ListBox Classes="launcher_page_tabbar"
|
||||
<ListBox x:Name="LauncherTabsList"
|
||||
Classes="launcher_page_tabbar"
|
||||
ItemsSource="{Binding Pages}"
|
||||
SelectionMode="AlwaysSelected"
|
||||
SelectedItem="{Binding ActivePage, Mode=TwoWay}">
|
||||
SelectedItem="{Binding ActivePage, Mode=TwoWay}"
|
||||
SelectionChanged="OnTabsSelectionChanged"
|
||||
LayoutUpdated="OnTabsLayoutUpdated">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" Height="30"/>
|
||||
|
@ -34,10 +37,8 @@
|
|||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:LauncherPage}">
|
||||
<Border Classes="launcher_pagetab"
|
||||
Height="30"
|
||||
BorderThickness="1,1,1,0"
|
||||
CornerRadius="6,6,0,0"
|
||||
<Border Height="30"
|
||||
Background="Transparent"
|
||||
PointerPressed="OnPointerPressedTab"
|
||||
PointerMoved="OnPointerMovedOverTab"
|
||||
PointerReleased="OnPointerReleasedTab"
|
||||
|
@ -86,11 +87,6 @@
|
|||
</ToolTip.Tip>
|
||||
<Path Width="8" Height="8" Data="{StaticResource Icons.Window.Close}"/>
|
||||
</Button>
|
||||
<Rectangle Grid.Column="2"
|
||||
Width=".5" Height="20"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Fill="{DynamicResource Brush.FG2}"
|
||||
IsVisible="{Binding IsTabSplitterVisible}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
|
|
|
@ -4,6 +4,7 @@ using Avalonia;
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
|
@ -14,6 +15,98 @@ namespace SourceGit.Views
|
|||
InitializeComponent();
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
base.Render(context);
|
||||
|
||||
if (LauncherTabsList == null || LauncherTabsList.SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
var startX = LauncherTabsScroller.Offset.X;
|
||||
var endX = startX + LauncherTabsScroller.Viewport.Width;
|
||||
var height = LauncherTabsScroller.Viewport.Height;
|
||||
|
||||
var selectedIdx = LauncherTabsList.SelectedIndex;
|
||||
var count = LauncherTabsList.ItemCount;
|
||||
var separatorPen = new Pen(this.FindResource("Brush.FG2") as IBrush, 0.5);
|
||||
var separatorY = (height - 20) * 0.5;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (i == selectedIdx || i == selectedIdx - 1)
|
||||
continue;
|
||||
|
||||
var container = LauncherTabsList.ContainerFromIndex(i);
|
||||
var containerEndX = container.Bounds.Right;
|
||||
if (containerEndX < startX || containerEndX > endX)
|
||||
continue;
|
||||
|
||||
var separatorX = containerEndX - startX + LauncherTabsScroller.Bounds.X;
|
||||
context.DrawLine(separatorPen, new Point(separatorX, separatorY), new Point(separatorX, separatorY + 20));
|
||||
}
|
||||
|
||||
var selected = LauncherTabsList.ContainerFromIndex(selectedIdx);
|
||||
var activeStartX = selected.Bounds.X;
|
||||
var activeEndX = activeStartX + selected.Bounds.Width;
|
||||
if (activeStartX > endX + 6 || activeEndX < startX - 6)
|
||||
return;
|
||||
|
||||
var geo = new StreamGeometry();
|
||||
var angle = Math.PI / 2;
|
||||
var x = 0.0;
|
||||
var y = height + 0.5;
|
||||
using (var ctx = geo.Open())
|
||||
{
|
||||
var drawLeftX = activeStartX - startX + LauncherTabsScroller.Bounds.X;
|
||||
var drawRightX = activeEndX - startX + LauncherTabsScroller.Bounds.X;
|
||||
if (drawLeftX < LauncherTabsScroller.Bounds.X)
|
||||
{
|
||||
x = LauncherTabsScroller.Bounds.X;
|
||||
ctx.BeginFigure(new Point(x, y), true);
|
||||
y = 0;
|
||||
ctx.LineTo(new Point(x, y));
|
||||
x = drawRightX - 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = drawLeftX - 6;
|
||||
ctx.BeginFigure(new Point(x, y), true);
|
||||
x = drawLeftX;
|
||||
y -= 6;
|
||||
ctx.ArcTo(new Point(x, y), new Size(6.5, 6.5), angle, false, SweepDirection.CounterClockwise);
|
||||
y = 6;
|
||||
ctx.LineTo(new Point(x, y));
|
||||
x += 6;
|
||||
y = 0;
|
||||
ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise);
|
||||
x = drawRightX - 6;
|
||||
}
|
||||
|
||||
if (drawRightX < LauncherTabsScroller.Bounds.Right)
|
||||
{
|
||||
ctx.LineTo(new Point(x, y));
|
||||
x = drawRightX;
|
||||
y = 6;
|
||||
ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise);
|
||||
y = height - 6;
|
||||
ctx.LineTo(new Point(x, y));
|
||||
x += 6;
|
||||
y = height + 0.5;
|
||||
ctx.ArcTo(new Point(x, y), new Size(6.5, 6.5), angle, false, SweepDirection.CounterClockwise);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = LauncherTabsScroller.Bounds.Right;
|
||||
ctx.LineTo(new Point(x, y));
|
||||
y = height + 0.5;
|
||||
ctx.LineTo(new Point(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
var fill = this.FindResource("Brush.ToolBar") as IBrush;
|
||||
var stroke = new Pen(this.FindResource("Brush.Border0") as IBrush, 1);
|
||||
context.DrawGeometry(fill, stroke, geo);
|
||||
}
|
||||
|
||||
private void ScrollTabs(object sender, PointerWheelEventArgs e)
|
||||
{
|
||||
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
||||
|
@ -52,6 +145,13 @@ namespace SourceGit.Views
|
|||
LeftScrollIndicator.IsVisible = false;
|
||||
RightScrollIndicator.IsVisible = false;
|
||||
}
|
||||
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private void OnTabsSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private void SetupDragAndDrop(object sender, RoutedEventArgs e)
|
||||
|
|
Loading…
Reference in a new issue