2024-03-17 18:37:06 -07:00
|
|
|
using System;
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
using Avalonia;
|
|
|
|
using Avalonia.Controls;
|
|
|
|
using Avalonia.Input;
|
|
|
|
using Avalonia.Interactivity;
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
namespace SourceGit.Views
|
|
|
|
{
|
|
|
|
public class LauncherTab : Grid
|
|
|
|
{
|
2024-02-29 22:09:39 -08:00
|
|
|
public static readonly StyledProperty<bool> UseFixedTabWidthProperty =
|
|
|
|
AvaloniaProperty.Register<LauncherTab, bool>(nameof(UseFixedTabWidth), false);
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
public bool UseFixedTabWidth
|
|
|
|
{
|
2024-02-29 22:09:39 -08:00
|
|
|
get => GetValue(UseFixedTabWidthProperty);
|
|
|
|
set => SetValue(UseFixedTabWidthProperty, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override Type StyleKeyOverride => typeof(Grid);
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
static LauncherTab()
|
|
|
|
{
|
|
|
|
UseFixedTabWidthProperty.Changed.AddClassHandler<LauncherTab>((tab, ev) =>
|
|
|
|
{
|
2024-02-29 22:09:39 -08:00
|
|
|
tab.Width = tab.UseFixedTabWidth ? 200.0 : double.NaN;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
public class LauncherBody : Border
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
public static readonly StyledProperty<object> DataProperty =
|
|
|
|
AvaloniaProperty.Register<LauncherBody, object>(nameof(Data), false);
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
public object Data
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
get => GetValue(DataProperty);
|
|
|
|
set => SetValue(DataProperty, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override Type StyleKeyOverride => typeof(Border);
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
static LauncherBody()
|
|
|
|
{
|
|
|
|
DataProperty.Changed.AddClassHandler<LauncherBody>((body, ev) =>
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
var data = body.Data;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
|
|
|
if (data == null)
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
body.Child = null;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else if (data is ViewModels.Welcome)
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
body.Child = new Welcome { DataContext = data };
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else if (data is ViewModels.Repository)
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
body.Child = new Repository { DataContext = data };
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-03-02 06:45:14 -08:00
|
|
|
body.Child = null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
public partial class Launcher : Window, Models.INotificationReceiver
|
|
|
|
{
|
|
|
|
public Launcher()
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
DataContext = new ViewModels.Launcher();
|
|
|
|
InitializeComponent();
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
public void OnReceiveNotification(string ctx, Models.Notification notice)
|
|
|
|
{
|
|
|
|
if (DataContext is ViewModels.Launcher vm)
|
|
|
|
{
|
|
|
|
foreach (var page in vm.Pages)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
var pageId = page.Node.Id.Replace("\\", "/");
|
2024-03-17 18:37:06 -07:00
|
|
|
if (pageId == ctx)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
page.Notifications.Add(notice);
|
2024-02-20 19:29:28 -08:00
|
|
|
return;
|
2024-02-05 23:08:37 -08:00
|
|
|
}
|
|
|
|
}
|
2024-02-20 19:29:28 -08:00
|
|
|
|
2024-03-31 01:54:29 -07:00
|
|
|
if (vm.ActivePage != null)
|
|
|
|
vm.ActivePage.Notifications.Add(notice);
|
2024-02-05 23:08:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
protected override void OnKeyDown(KeyEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
var vm = DataContext as ViewModels.Launcher;
|
2024-05-11 03:06:31 -07:00
|
|
|
|
|
|
|
// Ctrl+Shift+P opens preference dialog (macOS use hotkeys in system menu bar)
|
|
|
|
if (!OperatingSystem.IsMacOS() && e.KeyModifiers == (KeyModifiers.Control | KeyModifiers.Shift) && e.Key == Key.P)
|
|
|
|
{
|
|
|
|
App.OpenPreferenceCommand.Execute(null);
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-05-05 03:19:59 -07:00
|
|
|
if ((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Meta)) ||
|
|
|
|
(!OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Control)))
|
2024-03-17 18:37:06 -07:00
|
|
|
{
|
|
|
|
if (e.Key == Key.W)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
vm.CloseTab(null);
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
2024-05-05 03:19:59 -07:00
|
|
|
else if (e.Key == Key.T)
|
|
|
|
{
|
|
|
|
vm.AddNewTab();
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
|
|
|
}
|
2024-05-05 04:45:28 -07:00
|
|
|
else if ((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Alt) && e.Key == Key.Right) ||
|
2024-05-05 19:22:13 -07:00
|
|
|
(!OperatingSystem.IsMacOS() && !e.KeyModifiers.HasFlag(KeyModifiers.Shift) && e.Key == Key.Tab))
|
2024-03-17 18:37:06 -07:00
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
vm.GotoNextTab();
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
2024-05-05 19:22:13 -07:00
|
|
|
else if ((OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Alt) && e.Key == Key.Left) ||
|
|
|
|
(!OperatingSystem.IsMacOS() && e.KeyModifiers.HasFlag(KeyModifiers.Shift) && e.Key == Key.Tab))
|
|
|
|
{
|
|
|
|
vm.GotoPrevTab();
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
else if (vm.ActivePage.Data is ViewModels.Repository repo)
|
|
|
|
{
|
|
|
|
if (e.Key == Key.D1 || e.Key == Key.NumPad1)
|
|
|
|
{
|
2024-03-04 18:46:08 -08:00
|
|
|
repo.SelectedViewIndex = 0;
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else if (e.Key == Key.D2 || e.Key == Key.NumPad2)
|
|
|
|
{
|
2024-03-04 18:46:08 -08:00
|
|
|
repo.SelectedViewIndex = 1;
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else if (e.Key == Key.D3 || e.Key == Key.NumPad3)
|
|
|
|
{
|
2024-03-04 18:46:08 -08:00
|
|
|
repo.SelectedViewIndex = 2;
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else if (e.Key == Key.F)
|
|
|
|
{
|
2024-05-05 19:22:13 -07:00
|
|
|
repo.IsSearching = true;
|
2024-03-04 18:46:08 -08:00
|
|
|
e.Handled = true;
|
|
|
|
return;
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (e.Key == Key.Escape)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
vm.ActivePage.CancelPopup();
|
2024-05-05 19:22:13 -07:00
|
|
|
|
|
|
|
if (vm.ActivePage.Data is ViewModels.Repository repo)
|
|
|
|
{
|
|
|
|
repo.IsSearching = false;
|
|
|
|
}
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
e.Handled = true;
|
|
|
|
return;
|
|
|
|
}
|
2024-04-27 19:19:12 -07:00
|
|
|
else if (e.Key == Key.F5)
|
|
|
|
{
|
|
|
|
if (vm.ActivePage.Data is ViewModels.Repository repo)
|
|
|
|
{
|
|
|
|
repo.RefreshAll();
|
|
|
|
e.Handled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2024-02-05 23:08:37 -08:00
|
|
|
|
|
|
|
base.OnKeyDown(e);
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
protected override void OnClosing(WindowClosingEventArgs e)
|
|
|
|
{
|
2024-02-19 03:54:53 -08:00
|
|
|
var vm = DataContext as ViewModels.Launcher;
|
|
|
|
vm.Quit();
|
|
|
|
|
2024-02-05 23:08:37 -08:00
|
|
|
base.OnClosing(e);
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
|
|
|
{
|
|
|
|
if (WindowState == WindowState.Maximized)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
WindowState = WindowState.Normal;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
WindowState = WindowState.Maximized;
|
|
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
|
|
|
{
|
|
|
|
if (sender is Border border)
|
|
|
|
{
|
|
|
|
if (border.Tag is WindowEdge edge)
|
|
|
|
{
|
2024-03-14 03:23:36 -07:00
|
|
|
BeginResizeDrag(edge, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
BeginMoveDrag(e);
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void ScrollTabs(object sender, PointerWheelEventArgs e)
|
|
|
|
{
|
|
|
|
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
|
|
|
{
|
2024-03-31 01:54:29 -07:00
|
|
|
if (e.Delta.Y < 0)
|
|
|
|
launcherTabsScroller.LineRight();
|
2024-05-11 06:51:57 -07:00
|
|
|
else if (e.Delta.Y > 0)
|
2024-03-31 01:54:29 -07:00
|
|
|
launcherTabsScroller.LineLeft();
|
2024-02-05 23:08:37 -08:00
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void ScrollTabsLeft(object sender, RoutedEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
launcherTabsScroller.LineLeft();
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void ScrollTabsRight(object sender, RoutedEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
launcherTabsScroller.LineRight();
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void UpdateScrollIndicator(object sender, SizeChangedEventArgs e)
|
|
|
|
{
|
|
|
|
if (launcherTabsBar.Bounds.Width > launcherTabsContainer.Bounds.Width)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
leftScrollIndicator.IsVisible = true;
|
|
|
|
rightScrollIndicator.IsVisible = true;
|
2024-03-17 18:37:06 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
leftScrollIndicator.IsVisible = false;
|
|
|
|
rightScrollIndicator.IsVisible = false;
|
|
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-05-11 06:59:37 -07:00
|
|
|
private void OnTabsScrollChanged(object sender, ScrollChangedEventArgs e)
|
|
|
|
{
|
|
|
|
if (sender is ScrollViewer scrollViewer)
|
|
|
|
{
|
|
|
|
leftScrollIndicator.IsEnabled = scrollViewer.Offset.X > 0;
|
|
|
|
rightScrollIndicator.IsEnabled = scrollViewer.Offset.X < scrollViewer.Extent.Width - scrollViewer.Viewport.Width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void SetupDragAndDrop(object sender, RoutedEventArgs e)
|
|
|
|
{
|
|
|
|
if (sender is Border border)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
DragDrop.SetAllowDrop(border, true);
|
|
|
|
border.AddHandler(DragDrop.DropEvent, DropTab);
|
|
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void OnPointerPressedTab(object sender, PointerPressedEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
_pressedTab = true;
|
|
|
|
_startDrag = false;
|
|
|
|
_pressedTabPosition = e.GetPosition(sender as Border);
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void OnPointerReleasedTab(object sender, PointerReleasedEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
_pressedTab = false;
|
|
|
|
_startDrag = false;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void OnPointerMovedOverTab(object sender, PointerEventArgs e)
|
|
|
|
{
|
|
|
|
if (_pressedTab && !_startDrag && sender is Border border)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
var delta = e.GetPosition(border) - _pressedTabPosition;
|
|
|
|
var sizeSquired = delta.X * delta.X + delta.Y * delta.Y;
|
2024-03-31 01:54:29 -07:00
|
|
|
if (sizeSquired < 64)
|
|
|
|
return;
|
2024-02-05 23:08:37 -08:00
|
|
|
|
|
|
|
_startDrag = true;
|
|
|
|
|
|
|
|
var data = new DataObject();
|
|
|
|
data.Set("MovedTab", border.DataContext);
|
|
|
|
DragDrop.DoDragDrop(e, data, DragDropEffects.Move);
|
|
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void DropTab(object sender, DragEventArgs e)
|
|
|
|
{
|
|
|
|
if (e.Data.Contains("MovedTab") && sender is Border border)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
var to = border.DataContext as ViewModels.LauncherPage;
|
|
|
|
var moved = e.Data.Get("MovedTab") as ViewModels.LauncherPage;
|
2024-03-17 18:37:06 -07:00
|
|
|
if (to != null && moved != null && to != moved && DataContext is ViewModels.Launcher vm)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
vm.MoveTab(moved, to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_pressedTab = false;
|
|
|
|
_startDrag = false;
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void OnPopupSure(object sender, RoutedEventArgs e)
|
|
|
|
{
|
|
|
|
if (DataContext is ViewModels.Launcher vm)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
vm.ActivePage.ProcessPopup();
|
|
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void OnPopupCancel(object sender, RoutedEventArgs e)
|
|
|
|
{
|
|
|
|
if (DataContext is ViewModels.Launcher vm)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
vm.ActivePage.CancelPopup();
|
|
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
}
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
private void OnPopupCancelByClickMask(object sender, PointerPressedEventArgs e)
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
OnPopupCancel(sender, e);
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool _pressedTab = false;
|
|
|
|
private Point _pressedTabPosition = new Point();
|
2024-03-17 18:37:06 -07:00
|
|
|
private bool _startDrag = false;
|
2024-02-05 23:08:37 -08:00
|
|
|
}
|
2024-03-31 01:54:29 -07:00
|
|
|
}
|