454 строки
11 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|