Skip to content

Commit 1241539

Browse files
committed
refactor: custom renderer for launcher tab bar
1 parent bfea573 commit 1241539

File tree

6 files changed

+112
-47
lines changed

6 files changed

+112
-47
lines changed

src/Resources/Styles.axaml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -627,10 +627,6 @@
627627
</Setter>
628628
</Style>
629629

630-
<Style Selector="Border.launcher_pagetab">
631-
<Setter Property="Background" Value="Transparent"/>
632-
<Setter Property="BorderBrush" Value="Transparent"/>
633-
</Style>
634630
<Style Selector="ListBox.launcher_page_tabbar">
635631
<Setter Property="Background" Value="Transparent"/>
636632
</Style>
@@ -642,15 +638,13 @@
642638
<Setter Property="Opacity" Value=".5"/>
643639
</Style>
644640
<Style Selector="ListBox.launcher_page_tabbar ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
641+
<Setter Property="Background" Value="Transparent"/>
645642
<Setter Property="Opacity" Value=".85"/>
646643
</Style>
647644
<Style Selector="ListBox.launcher_page_tabbar ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
645+
<Setter Property="Background" Value="Transparent"/>
648646
<Setter Property="Opacity" Value="1"/>
649647
</Style>
650-
<Style Selector="ListBoxItem:selected Border.launcher_pagetab">
651-
<Setter Property="Background" Value="{DynamicResource Brush.ToolBar}"/>
652-
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
653-
</Style>
654648

655649
<Style Selector="ContextMenu">
656650
<Setter Property="HorizontalOffset" Value="-4"/>

src/ViewModels/Launcher.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ public LauncherPage ActivePage
2424
set
2525
{
2626
if (SetProperty(ref _activePage, value))
27-
{
2827
PopupHost.Active = value;
29-
UpdateTabSplitterVisible();
30-
}
3128
}
3229
}
3330

@@ -69,9 +66,7 @@ public Launcher()
6966

7067
var lastActiveIdx = Preference.Instance.LastActiveTabIdx;
7168
if (lastActiveIdx >= 0 && lastActiveIdx < Pages.Count)
72-
{
7369
ActivePage = Pages[lastActiveIdx];
74-
}
7570
}
7671
}
7772

@@ -161,13 +156,11 @@ public void CloseTab(LauncherPage page)
161156
ActivePage = Pages[removeIdx == Pages.Count - 1 ? removeIdx - 1 : removeIdx + 1];
162157
CloseRepositoryInTab(page);
163158
Pages.RemoveAt(removeIdx);
164-
UpdateTabSplitterVisible();
165159
}
166160
else if (removeIdx + 1 == activeIdx)
167161
{
168162
CloseRepositoryInTab(page);
169163
Pages.RemoveAt(removeIdx);
170-
UpdateTabSplitterVisible();
171164
}
172165
else
173166
{
@@ -365,13 +358,6 @@ private void CloseRepositoryInTab(LauncherPage page)
365358
page.Data = null;
366359
}
367360

368-
private void UpdateTabSplitterVisible()
369-
{
370-
var activePageIdx = ActivePage == null ? -1 : Pages.IndexOf(ActivePage);
371-
for (int i = 0; i < Pages.Count; i++)
372-
Pages[i].IsTabSplitterVisible = (activePageIdx != i && activePageIdx != i + 1);
373-
}
374-
375361
private LauncherPage _activePage = null;
376362
}
377363
}

src/ViewModels/LauncherPage.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ public object Data
1818
set => SetProperty(ref _data, value);
1919
}
2020

21-
public bool IsTabSplitterVisible
22-
{
23-
get => _isTabSplitterVisible;
24-
set => SetProperty(ref _isTabSplitterVisible, value);
25-
}
26-
2721
public AvaloniaList<Notification> Notifications
2822
{
2923
get;
@@ -55,6 +49,5 @@ public void CopyPath()
5549

5650
private RepositoryNode _node = null;
5751
private object _data = null;
58-
private bool _isTabSplitterVisible = true;
5952
}
6053
}

src/Views/Launcher.axaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@
3737
</Border>
3838

3939
<!-- Menu (Windows/Linux) -->
40-
<Button Grid.Column="0" Classes="icon_button" VerticalAlignment="Bottom" IsVisible="{OnPlatform True, macOS=False}">
41-
<Button.Margin>
42-
<OnPlatform Default="4,0,2,3" macOS="4,0,6,3"/>
43-
</Button.Margin>
44-
40+
<Button Grid.Column="0" Classes="icon_button" VerticalAlignment="Bottom" Margin="6,0,2,3" IsVisible="{OnPlatform True, macOS=False}">
4541
<Button.Flyout>
4642
<MenuFlyout Placement="BottomEdgeAlignedLeft" VerticalOffset="-8">
4743
<MenuItem Header="{DynamicResource Text.Preference}" Command="{x:Static s:App.OpenPreferenceCommand}" InputGesture="Ctrl+Shift+P">

src/Views/LauncherTabBar.axaml

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@
1515
</RepeatButton>
1616

1717
<ScrollViewer Grid.Column="1"
18+
Margin="6,0"
1819
x:Name="LauncherTabsScroller"
1920
HorizontalAlignment="Left"
2021
HorizontalScrollBarVisibility="Hidden"
2122
VerticalScrollBarVisibility="Disabled"
22-
PointerWheelChanged="ScrollTabs"
23-
LayoutUpdated="OnTabsLayoutUpdated">
23+
PointerWheelChanged="ScrollTabs">
2424
<StackPanel Orientation="Horizontal">
25-
<ListBox Classes="launcher_page_tabbar"
25+
<ListBox x:Name="LauncherTabsList"
26+
Classes="launcher_page_tabbar"
2627
ItemsSource="{Binding Pages}"
2728
SelectionMode="AlwaysSelected"
28-
SelectedItem="{Binding ActivePage, Mode=TwoWay}">
29+
SelectedItem="{Binding ActivePage, Mode=TwoWay}"
30+
SelectionChanged="OnTabsSelectionChanged"
31+
LayoutUpdated="OnTabsLayoutUpdated">
2932
<ListBox.ItemsPanel>
3033
<ItemsPanelTemplate>
3134
<StackPanel Orientation="Horizontal" Height="30"/>
@@ -34,10 +37,8 @@
3437

3538
<ListBox.ItemTemplate>
3639
<DataTemplate DataType="{x:Type vm:LauncherPage}">
37-
<Border Classes="launcher_pagetab"
38-
Height="30"
39-
BorderThickness="1,1,1,0"
40-
CornerRadius="6,6,0,0"
40+
<Border Height="30"
41+
Background="Transparent"
4142
PointerPressed="OnPointerPressedTab"
4243
PointerMoved="OnPointerMovedOverTab"
4344
PointerReleased="OnPointerReleasedTab"
@@ -86,11 +87,6 @@
8687
</ToolTip.Tip>
8788
<Path Width="8" Height="8" Data="{StaticResource Icons.Window.Close}"/>
8889
</Button>
89-
<Rectangle Grid.Column="2"
90-
Width=".5" Height="20"
91-
HorizontalAlignment="Right" VerticalAlignment="Center"
92-
Fill="{DynamicResource Brush.FG2}"
93-
IsVisible="{Binding IsTabSplitterVisible}"/>
9490
</Grid>
9591
</Border>
9692
</DataTemplate>

src/Views/LauncherTabBar.axaml.cs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Avalonia.Controls;
55
using Avalonia.Input;
66
using Avalonia.Interactivity;
7+
using Avalonia.Media;
78

89
namespace SourceGit.Views
910
{
@@ -14,6 +15,98 @@ public LauncherTabBar()
1415
InitializeComponent();
1516
}
1617

18+
public override void Render(DrawingContext context)
19+
{
20+
base.Render(context);
21+
22+
if (LauncherTabsList == null || LauncherTabsList.SelectedIndex == -1)
23+
return;
24+
25+
var startX = LauncherTabsScroller.Offset.X;
26+
var endX = startX + LauncherTabsScroller.Viewport.Width;
27+
var height = LauncherTabsScroller.Viewport.Height;
28+
29+
var selectedIdx = LauncherTabsList.SelectedIndex;
30+
var count = LauncherTabsList.ItemCount;
31+
var separatorPen = new Pen(this.FindResource("Brush.FG2") as IBrush, 0.5);
32+
var separatorY = (height - 20) * 0.5;
33+
for (var i = 0; i < count; i++)
34+
{
35+
if (i == selectedIdx || i == selectedIdx - 1)
36+
continue;
37+
38+
var container = LauncherTabsList.ContainerFromIndex(i);
39+
var containerEndX = container.Bounds.Right;
40+
if (containerEndX < startX || containerEndX > endX)
41+
continue;
42+
43+
var separatorX = containerEndX - startX + LauncherTabsScroller.Bounds.X;
44+
context.DrawLine(separatorPen, new Point(separatorX, separatorY), new Point(separatorX, separatorY + 20));
45+
}
46+
47+
var selected = LauncherTabsList.ContainerFromIndex(selectedIdx);
48+
var activeStartX = selected.Bounds.X;
49+
var activeEndX = activeStartX + selected.Bounds.Width;
50+
if (activeStartX > endX + 6 || activeEndX < startX - 6)
51+
return;
52+
53+
var geo = new StreamGeometry();
54+
var angle = Math.PI / 2;
55+
var x = 0.0;
56+
var y = height + 0.5;
57+
using (var ctx = geo.Open())
58+
{
59+
var drawLeftX = activeStartX - startX + LauncherTabsScroller.Bounds.X;
60+
var drawRightX = activeEndX - startX + LauncherTabsScroller.Bounds.X;
61+
if (drawLeftX < LauncherTabsScroller.Bounds.X)
62+
{
63+
x = LauncherTabsScroller.Bounds.X;
64+
ctx.BeginFigure(new Point(x, y), true);
65+
y = 0;
66+
ctx.LineTo(new Point(x, y));
67+
x = drawRightX - 6;
68+
}
69+
else
70+
{
71+
x = drawLeftX - 6;
72+
ctx.BeginFigure(new Point(x, y), true);
73+
x = drawLeftX;
74+
y -= 6;
75+
ctx.ArcTo(new Point(x, y), new Size(6.5, 6.5), angle, false, SweepDirection.CounterClockwise);
76+
y = 6;
77+
ctx.LineTo(new Point(x, y));
78+
x += 6;
79+
y = 0;
80+
ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise);
81+
x = drawRightX - 6;
82+
}
83+
84+
if (drawRightX < LauncherTabsScroller.Bounds.Right)
85+
{
86+
ctx.LineTo(new Point(x, y));
87+
x = drawRightX;
88+
y = 6;
89+
ctx.ArcTo(new Point(x, y), new Size(6, 6), angle, false, SweepDirection.Clockwise);
90+
y = height - 6;
91+
ctx.LineTo(new Point(x, y));
92+
x += 6;
93+
y = height + 0.5;
94+
ctx.ArcTo(new Point(x, y), new Size(6.5, 6.5), angle, false, SweepDirection.CounterClockwise);
95+
}
96+
else
97+
{
98+
x = LauncherTabsScroller.Bounds.Right;
99+
ctx.LineTo(new Point(x, y));
100+
y = height + 0.5;
101+
ctx.LineTo(new Point(x, y));
102+
}
103+
}
104+
105+
var fill = this.FindResource("Brush.ToolBar") as IBrush;
106+
var stroke = new Pen(this.FindResource("Brush.Border0") as IBrush, 1);
107+
context.DrawGeometry(fill, stroke, geo);
108+
}
109+
17110
private void ScrollTabs(object sender, PointerWheelEventArgs e)
18111
{
19112
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
@@ -52,6 +145,13 @@ private void OnTabsLayoutUpdated(object sender, EventArgs e)
52145
LeftScrollIndicator.IsVisible = false;
53146
RightScrollIndicator.IsVisible = false;
54147
}
148+
149+
InvalidateVisual();
150+
}
151+
152+
private void OnTabsSelectionChanged(object sender, SelectionChangedEventArgs e)
153+
{
154+
InvalidateVisual();
55155
}
56156

57157
private void SetupDragAndDrop(object sender, RoutedEventArgs e)

0 commit comments

Comments
 (0)