maui-linux/Xamarin.Forms.Platform.GTK/GtkToolbarTracker.cs

454 строки
11 KiB
C#

using Gdk;
using Gtk;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.GTK.Controls;
using Xamarin.Forms.Platform.GTK.Extensions;
using Xamarin.Forms.Platform.GTK.Renderers;
namespace Xamarin.Forms.Platform.GTK
{
public class GtkToolbarTracker
{
private readonly string _defaultBackButtonTitle = "Back";
private readonly ToolbarTracker _toolbarTracker;
private HBox _toolbar;
private HBox _toolbarNavigationSection;
private Alignment _toolbarTitleSectionWrapper;
private HBox _toolbarTitleSection;
private HBox _toolbarSection;
private Gtk.Label _toolbarTitle;
private ImageControl _toolbarIcon;
private NavigationPage _navigation;
private string _backButton;
private MasterDetailPage _parentMasterDetailPage;
public GtkToolbarTracker()
{
_toolbarTracker = new ToolbarTracker();
_toolbarTracker.CollectionChanged += ToolbarTrackerOnCollectionChanged;
}
public HBox Toolbar
{
get { return _toolbar; }
}
public NavigationPage Navigation
{
get { return _navigation; }
set
{
if (_navigation == value)
return;
if (_navigation != null)
_navigation.PropertyChanged -= NavigationPagePropertyChanged;
_navigation = value;
if (_navigation != null)
{
_toolbarTracker.Target = _navigation.CurrentPage;
_navigation.PropertyChanged += NavigationPagePropertyChanged;
}
UpdateToolBar();
}
}
public void TryHide(NavigationPage navPage = null)
{
if (navPage == null || navPage == _navigation)
{
Navigation = null;
}
}
public void UpdateIcon()
{
if (_toolbar == null || _navigation == null)
return;
_toolbarIcon.WidthRequest = 1;
_ = _navigation?.Peek(0)?.ApplyNativeImageAsync(Page.IconImageSourceProperty, icon =>
{
if (icon != null)
{
_toolbarIcon.Pixbuf = icon;
_toolbarIcon.SetSizeRequest(GtkToolbarConstants.ToolbarIconWidth, GtkToolbarConstants.ToolbarIconHeight);
}
});
}
public void UpdateTitle()
{
if (_toolbar == null || _navigation == null)
return;
var title = GetCurrentPageTitle();
if (_toolbarTitle != null)
{
var span = new Span()
{
FontSize = 12.0d,
Text = title ?? string.Empty
};
_toolbarTitle.SetTextFromSpan(span);
}
}
protected virtual HBox ConfigureToolbar()
{
var toolbar = new HBox();
toolbar.HeightRequest = GtkToolbarConstants.ToolbarHeight;
_toolbarNavigationSection = new HBox();
toolbar.PackStart(_toolbarNavigationSection, false, true, 0);
_toolbarTitleSectionWrapper = new Alignment(0f, 0.5f, 0, 0);
_toolbarTitleSection = new HBox();
_toolbarTitleSectionWrapper.Add(_toolbarTitleSection);
toolbar.PackStart(_toolbarTitleSectionWrapper, true, true, 0);
_toolbarSection = new HBox();
toolbar.PackStart(_toolbarSection, false, true, 0);
return toolbar;
}
private void ToolbarTrackerOnCollectionChanged(object sender, EventArgs eventArgs)
{
UpdateToolbarItems();
}
private void UpdateToolbarItems()
{
if (_toolbar == null || _navigation == null)
return;
var currentPage = _navigation.Peek(0);
UpdateItems(currentPage.ToolbarItems);
}
private void NavigationPagePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals(NavigationPage.BarTextColorProperty.PropertyName) ||
e.PropertyName.Equals(NavigationPage.BarBackgroundColorProperty.PropertyName) ||
e.PropertyName.Equals(NavigationPage.HasNavigationBarProperty.PropertyName) ||
e.PropertyName.Equals(Page.TitleProperty.PropertyName) ||
e.PropertyName.Equals(Page.IconImageSourceProperty.PropertyName))
UpdateToolBar();
}
private string GetCurrentPageTitle()
{
if (_navigation == null)
return string.Empty;
return _navigation.Peek(0).Title ?? string.Empty;
}
private void UpdateBarBackgroundColor(Controls.Page page)
{
if (Navigation != null)
{
page?.SetToolbarColor(Navigation.BarBackgroundColor);
}
}
private void UpdateBarTextColor()
{
if (Navigation != null && Navigation.BarTextColor != Color.Default)
{
var textColor = Navigation.BarTextColor.ToGtkColor();
if (_toolbar != null && _toolbarTitle != null)
{
_toolbarTitle.ModifyFg(StateType.Normal, textColor);
}
}
}
private void UpdateBarBackgroundColor()
{
var currentPage = _navigation.Peek(0);
var pageRenderer = Platform.GetRenderer(currentPage);
if (pageRenderer != null && pageRenderer.Disposed)
{
return;
}
var page = pageRenderer as IPageControl;
if (page?.Control != null)
{
page.Control.Toolbar = _toolbar;
UpdateBarBackgroundColor(page.Control);
}
}
private void UpdateItems(IList<ToolbarItem> toolBarItems)
{
foreach (var child in _toolbarSection.Children)
{
child.Destroy();
_toolbarSection.Remove(child);
}
foreach (var toolBarItem in toolBarItems.Where(t => t.Order != ToolbarItemOrder.Secondary))
{
ToolButton newToolButton = ToolButtonHelper.CreateToolButton(toolBarItem);
_toolbarSection.PackStart(newToolButton, false, false, GtkToolbarConstants.ToolbarItemSpacing);
newToolButton.Clicked += (sender, args) => { ((IMenuItemController)toolBarItem).Activate(); };
toolBarItem.PropertyChanged -= OnToolbarItemPropertyChanged;
toolBarItem.PropertyChanged += OnToolbarItemPropertyChanged;
}
var secondaryToolBarItems = toolBarItems.Where(t => t.Order == ToolbarItemOrder.Secondary);
if (secondaryToolBarItems.Any())
{
ToolButton secondaryButton = ToolButtonHelper.CreateToolButton(Stock.Add);
_toolbarSection.PackStart(secondaryButton, false, false, 0);
Gtk.Menu menu = new Gtk.Menu();
foreach (var secondaryToolBarItem in secondaryToolBarItems)
{
Gtk.MenuItem menuItem = new Gtk.MenuItem(secondaryToolBarItem.Text)
{
Sensitive = secondaryToolBarItem.IsEnabled
};
menu.Add(menuItem);
menuItem.ButtonPressEvent += (sender, args) =>
{
((IMenuItemController)secondaryToolBarItem).Activate();
};
secondaryToolBarItem.PropertyChanged -= OnToolbarItemPropertyChanged;
secondaryToolBarItem.PropertyChanged += OnToolbarItemPropertyChanged;
}
secondaryButton.Clicked += (sender, args) =>
{
menu.ShowAll();
menu.Popup();
};
}
_toolbarSection.ShowAll();
}
private bool ShowBackButton()
{
if (_navigation == null)
return false;
return NavigationPage.GetHasBackButton(_navigation.CurrentPage)
&& !IsRootPage();
}
private bool IsRootPage()
{
if (_navigation == null)
return true;
return _navigation.StackDepth <= 1;
}
private void UpdateNavigationItems()
{
if (_toolbar == null || _navigation == null)
return;
if (ShowBackButton())
{
ToolButton navigationButton;
if (string.IsNullOrEmpty(_backButton))
{
navigationButton = ToolButtonHelper.CreateToolButton(Stock.GoBack);
}
else
{
navigationButton = ToolButtonHelper.CreateToolButton(_backButton, string.Empty);
}
navigationButton.TooltipText = GetPreviousPageTitle() ?? string.Empty;
navigationButton.WidthRequest = GtkToolbarConstants.BackButtonItemWidth;
_toolbarNavigationSection.PackStart(navigationButton, false, false, GtkToolbarConstants.ToolbarItemSpacing);
navigationButton.Clicked += async (sender, args) =>
{
await NavigateBackFromBackButton();
};
}
else if (_parentMasterDetailPage != null && _parentMasterDetailPage.ShouldShowToolbarButton())
{
ToolButton hamburguerButton = new ToolButton(null, string.Empty);
var hamburgerPixBuf = Controls.MasterDetailPage.HamburgerPixBuf;
if (hamburgerPixBuf != null)
{
var image = new Gtk.Image(hamburgerPixBuf);
hamburguerButton = new ToolButton(image, string.Empty);
}
hamburguerButton.HeightRequest = GtkToolbarConstants.ToolbarItemHeight;
hamburguerButton.WidthRequest = GtkToolbarConstants.BackButtonItemWidth;
_toolbarNavigationSection.PackStart(hamburguerButton, false, false, GtkToolbarConstants.ToolbarItemSpacing);
hamburguerButton.Clicked += (sender, args) =>
{
_parentMasterDetailPage.IsPresented = !_parentMasterDetailPage.IsPresented;
};
}
}
private string GetPreviousPageTitle()
{
if (_navigation == null || _navigation.StackDepth <= 1)
return string.Empty;
return _navigation.Peek(1).Title ?? _defaultBackButtonTitle;
}
private async Task NavigateBackFromBackButton()
{
var popAsyncInner = _navigation?.PopAsyncInner(true, true);
if (popAsyncInner != null)
await popAsyncInner;
}
private void FindParentMasterDetail()
{
var masterDetailPage = _navigation.GetParentsPath()
.OfType<MasterDetailPage>()
.Where(md => md.Detail == _navigation)
.FirstOrDefault();
_parentMasterDetailPage = masterDetailPage;
}
internal void UpdateBackButton(string backButton)
{
_backButton = backButton;
}
internal void UpdateToolBar()
{
if (_navigation == null)
{
if (_toolbar != null)
_toolbar.Visible = false;
_toolbar = null;
return;
}
var currentPage = _navigation.Peek(0);
if (NavigationPage.GetHasNavigationBar(currentPage))
{
if (_toolbar == null)
{
_toolbar = ConfigureToolbar();
_toolbarIcon = new ImageControl
{
WidthRequest = 1,
Aspect = ImageAspect.AspectFit
};
_toolbarTitleSection.PackStart(_toolbarIcon, false, false, 8);
_toolbarTitle = new Gtk.Label();
_toolbarTitleSection.PackEnd(_toolbarTitle, true, true, 0);
}
FindParentMasterDetail();
UpdateNavigationItems();
UpdateTitle();
UpdateIcon();
UpdateToolbarItems();
UpdateBarTextColor();
UpdateBarBackgroundColor();
}
else
{
if (_toolbar != null)
{
_toolbar.Visible = false;
}
}
}
internal void ResetToolBar()
{
_toolbar = null;
}
private void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName)
UpdateToolbarItems();
else if (e.PropertyName == MenuItem.TextProperty.PropertyName)
UpdateToolbarItems();
else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
UpdateToolbarItems();
}
static class ToolButtonHelper
{
public static ToolButton CreateToolButton(string stockId)
{
ToolButton button = new ToolButton(stockId);
ApplyDefaultDimensions(button);
return button;
}
public static ToolButton CreateToolButton(string iconFileName, string title)
{
var pixBuf = new Pixbuf(iconFileName);
var image = new Gtk.Image(pixBuf);
ToolButton button = new ToolButton(image, title);
ApplyDefaultDimensions(button);
return button;
}
public static ToolButton CreateToolButton(ToolbarItem item)
{
var pixBuf = item.IconImageSource.ToPixbuf();
Gtk.Image icon = pixBuf != null ? new Gtk.Image(pixBuf) : null;
ToolButton button = new ToolButton(icon, item.Text);
ApplyDefaultDimensions(button);
button.TooltipText = item.Text ?? string.Empty;
button.Sensitive = item.IsEnabled;
return button;
}
private static void ApplyDefaultDimensions(ToolButton button)
{
button.HeightRequest = GtkToolbarConstants.ToolbarItemHeight;
button.WidthRequest = GtkToolbarConstants.ToolbarItemWidth;
}
}
}
}