using System;
using ElmSharp;
namespace Xamarin.Forms.Platform.Tizen.Native
{
///
/// The native widget which provides Xamarin.MasterDetailPage features.
///
public class MasterDetailPage : Box
{
///
/// The portion of the screen that the MasterPage takes in Split mode.
///
static readonly double s_splitRatio = 0.35;
///
/// The portion of the screen that the MasterPage takes in Popover mode.
///
static readonly double s_popoverRatio = 0.8;
///
/// The default master behavior (a.k.a mode).
///
static readonly MasterBehavior s_defaultMasterBehavior = (Device.Idiom == TargetIdiom.Phone) ? MasterBehavior.Popover : MasterBehavior.SplitOnLandscape;
///
/// The MasterPage native container.
///
readonly Canvas _masterCanvas;
///
/// The DetailPage native container.
///
readonly Canvas _detailCanvas;
///
/// The container for _masterCanvas and _detailCanvas used in split mode.
///
readonly Panes _splitPane;
///
/// The container for _masterCanvas used in popover mode.
///
readonly Panel _drawer;
///
/// The property value.
///
MasterBehavior _masterBehavior = s_defaultMasterBehavior;
///
/// The actual MasterDetailPage mode - either split or popover. It depends on _masterBehavior and screen orientation.
///
MasterBehavior _internalMasterBehavior = MasterBehavior.Popover;
///
/// The property value.
///
EvasObject _master;
///
/// The property value.
///
EvasObject _detail;
///
/// The main widget - either or , depending on the mode.
///
EvasObject _mainWidget;
///
/// The property value.
///
bool _isGestureEnabled;
///
/// Initializes a new instance of the class.
///
/// Parent evas object.
public MasterDetailPage(EvasObject parent) : base(parent)
{
// we control the layout ourselves
Resized += (sender, e) =>
{
var g = Geometry;
// main widget should fill the area of the MasterDetailPage
if (_mainWidget != null)
{
_mainWidget.Geometry = g;
}
g.Width = (int)((s_popoverRatio * (double)g.Width));
_drawer.Geometry = g;
};
// create the controls which will hold the master and detail pages
_masterCanvas = new Canvas(this);
_masterCanvas.SetAlignment(-1.0, -1.0); // fill
_masterCanvas.SetWeight(1.0, 1.0); // expand
_masterCanvas.Resized += (sender, e) =>
{
UpdatePageGeometry(_master);
};
_detailCanvas = new Canvas(this);
_detailCanvas.SetAlignment(-1.0, -1.0); // fill
_detailCanvas.SetWeight(1.0, 1.0); // expand
_detailCanvas.Resized += (sender, e) =>
{
UpdatePageGeometry(_detail);
};
_splitPane = new Panes(this)
{
IsFixed = true,
IsHorizontal = false,
Proportion = s_splitRatio,
};
_drawer = new Panel(Forms.Context.MainWindow)
{
Direction = PanelDirection.Left,
};
_drawer.SetScrollable(_isGestureEnabled);
_drawer.SetScrollableArea(1.0);
_drawer.Toggled += (object sender, EventArgs e) =>
{
IsPresentedChanged?.Invoke(this, EventArgs.Empty);
};
ConfigureLayout();
// in case of the screen rotation we may need to update the choice between split
// and popover behaviors and reconfigure the layout
Forms.Context.MainWindow.RotationChanged += (sender, e) =>
{
UpdateMasterBehavior();
};
}
///
/// Occurs when the MasterPage is shown or hidden.
///
public event EventHandler IsPresentedChanged;
///
/// Gets or sets the MasterDetailPage behavior.
///
/// The behavior of the MasterDetailPage requested by the user.
public MasterBehavior MasterBehavior
{
get
{
return _masterBehavior;
}
set
{
if (_masterBehavior != value)
{
_masterBehavior = value;
UpdateMasterBehavior();
}
}
}
///
/// Gets or sets the content of the MasterPage.
///
/// The MasterPage.
public EvasObject Master
{
get
{
return _master;
}
set
{
if (_master != value)
{
_master = value;
UpdatePageGeometry(_master);
_masterCanvas.Children.Clear();
_masterCanvas.Children.Add(_master);
}
}
}
///
/// Gets or sets the content of the DetailPage.
///
/// The DetailPage.
public EvasObject Detail
{
get
{
return _detail;
}
set
{
if (_detail != value)
{
_detail = value;
UpdatePageGeometry(_detail);
_detailCanvas.Children.Clear();
_detailCanvas.Children.Add(_detail);
}
}
}
///
/// Gets or sets a value indicating whether the MasterPage is shown.
///
/// true if the MasterPage is presented.
public bool IsPresented
{
get
{
return _drawer.IsOpen;
}
set
{
if (_drawer.IsOpen != value)
{
_drawer.IsOpen = value;
}
}
}
///
/// Gets or sets a value indicating whether a MasterDetailPage allows showing MasterPage with swipe gesture.
///
/// true if the MasterPage can be revealed with a gesture.
public bool IsGestureEnabled
{
get
{
return _isGestureEnabled;
}
set
{
if (_isGestureEnabled != value)
{
_isGestureEnabled = value;
_drawer.SetScrollable(_isGestureEnabled);
}
}
}
///
/// Updates the geometry of the selected page.
///
/// Master or Detail page to be updated.
void UpdatePageGeometry(EvasObject page)
{
if (page != null)
{
if (_master == page)
{
// update the geometry of the master page
page.Geometry = _masterCanvas.Geometry;
}
else if (_detail == page)
{
// update the geometry of the detail page
page.Geometry = _detailCanvas.Geometry;
}
}
}
///
/// Updates according to set by the user and current screen orientation.
///
void UpdateMasterBehavior()
{
var behavior = (_masterBehavior == MasterBehavior.Default) ? s_defaultMasterBehavior : _masterBehavior;
// Screen orientation affects those 2 behaviors
if (behavior == MasterBehavior.SplitOnLandscape ||
behavior == MasterBehavior.SplitOnPortrait)
{
var orientation = Forms.Context.MainWindow.CurrentOrientation;
if (((orientation == DisplayOrientations.Landscape || orientation == DisplayOrientations.LandscapeFlipped) && behavior == MasterBehavior.SplitOnLandscape) ||
((orientation == DisplayOrientations.Portrait || orientation == DisplayOrientations.PortraitFlipped) && behavior == MasterBehavior.SplitOnPortrait))
{
behavior = MasterBehavior.Split;
}
else
{
behavior = MasterBehavior.Popover;
}
}
if (behavior != _internalMasterBehavior)
{
_internalMasterBehavior = behavior;
ConfigureLayout();
}
}
///
/// Composes the structure of all the necessary widgets.
///
void ConfigureLayout()
{
_drawer.SetContent(null, true);
_drawer.Hide();
_splitPane.SetPartContent("left", null, true);
_splitPane.SetPartContent("right", null, true);
_splitPane.Hide();
UnPackAll();
// the structure for split mode and for popover mode looks differently
if (_internalMasterBehavior == MasterBehavior.Split)
{
_splitPane.SetPartContent("left", _masterCanvas, true);
_splitPane.SetPartContent("right", _detailCanvas, true);
PackEnd(_splitPane);
_splitPane.Show();
_mainWidget = _splitPane;
IsPresented = true;
}
else
{
_drawer.SetContent(_masterCanvas, true);
PackEnd(_detailCanvas);
_drawer.Show();
_mainWidget = _detailCanvas;
_drawer.IsOpen = IsPresented;
}
_masterCanvas.Show();
_detailCanvas.Show();
}
}
}