--- /dev/null
+using System.Threading.Tasks;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Components;
+using System.Collections.Generic;
+using System;
+
+namespace ScalableUI
+{
+ public class OrientationalView : Tizen.NUI.BaseComponents.View
+ {
+ public enum Mode
+ {
+ Stacking,
+ Splitting,
+ };
+
+ public Mode LandscapeMode { get; set; } = Mode.Stacking;
+
+ public int SplittingSpacing { get; set; } = 0;
+
+ public OrientationalView()
+ {
+ Size2D = Window.Instance.Size;
+ PositionUsesPivotPoint = true;
+ ParentOrigin = Tizen.NUI.ParentOrigin.Center;
+ PivotPoint = Tizen.NUI.PivotPoint.Center;
+
+ ClippingMode = ClippingModeType.ClipToBoundingBox;
+ pageEnterAnimation = new Tizen.NUI.Animation();
+ pageLeaveAnimation = new Tizen.NUI.Animation();
+ opacityEffectAnimation = new Tizen.NUI.Animation();
+ pageEnterAnimation.Finished += OnPageEntered;
+ pageLeaveAnimation.Finished += OnPageLeave;
+ }
+
+ public override void Add(View child)
+ {
+ child.PositionUsesPivotPoint = false;
+
+ if (LandscapeMode == Mode.Stacking)
+ {
+ AddStacking(child);
+ }
+ else if (LandscapeMode == Mode.Splitting)
+ {
+ child.Hide();
+ base.Add(child);
+ AddSplitting(child);
+ }
+ }
+
+ public override async void Remove(View child)
+ {
+ if (LandscapeMode == Mode.Stacking)
+ {
+ await RemoveStacking(child);
+ }
+ else if (LandscapeMode == Mode.Splitting)
+ {
+ await RemoveSplitting(child);
+ base.Remove(child);
+ }
+ }
+
+ public void RemoveLastAdded()
+ {
+ if (Children.Any())
+ {
+ var last = Children.Last();
+ Remove(last);
+ }
+ }
+
+ private async void AddSplitting(View child)
+ {
+ if (Children.Count == 1)
+ {
+ int width = Size2D.Width - (Padding.Start + Padding.End);
+ int height = Size2D.Height - (Padding.Top + Padding.Bottom);
+
+ // show child behind right edge
+ child.Size2D = new Size2D(width, height);
+ child.Position2D = new Position2D(Size2D.Width, Padding.Top);
+ child.Show();
+
+ // slide left onto the vieport
+ await Animation.AnimateTo(child, "PositionX", (int)Padding.Start);
+ }
+ else if (Children.Count == 2)
+ {
+ int width = (Size2D.Width - (Padding.Start + Padding.End + SplittingSpacing)) / 2;
+ int height = Size2D.Height - (Padding.Top + Padding.Bottom);
+
+ var prev = Children.Skip(Children.Count - 2).First();
+
+ // reduce width
+ await Animation.AnimateTo(prev, "SizeWidth", width);
+ // FIX ME: animating SizeWidth does animate background, but not content => thus, required to reassign size
+ prev.Size2D = new Size2D(width, height);
+
+ // show child behind right edge
+ child.Size2D = new Size2D(width, height);
+ child.Position2D = new Position2D(Size2D.Width, Padding.Top);
+ child.Show();
+
+ // slide left onto the viewport
+ await Animation.AnimateTo(child, "PositionX", Padding.Start + width + SplittingSpacing);
+ }
+ else
+ {
+ int width = (Size2D.Width - (Padding.Start + Padding.End + SplittingSpacing)) / 2;
+ int height = Size2D.Height - (Padding.Top + Padding.Bottom);
+
+ var first = Children.Skip(Children.Count - 3).First();
+ var prev = Children.Skip(Children.Count - 2).First();
+
+ // slide left out of the viewport
+ await Animation.AnimateTo(first, "PositionX", -width);
+ first.Hide();
+
+ // slide left from right
+ await Animation.AnimateTo(prev, "PositionX", (int)Padding.Start);
+
+ // show child behind right edge
+ child.Size2D = new Size2D(width, height);
+ child.Position2D = new Position2D(Size2D.Width, Padding.Top);
+ child.Show();
+
+ // slide left onto the viewport
+ await Animation.AnimateTo(child, "PositionX", Padding.Start + width + SplittingSpacing);
+ }
+ }
+
+ private async Task RemoveSplitting(View child)
+ {
+ if (Children.Count == 1)
+ {
+ // slide right out of the viewport
+ await Animation.AnimateTo(child, "PositionX", Size2D.Width);
+ }
+ else if (Children.Count == 2)
+ {
+ int width = Size2D.Width - (Padding.Start + Padding.End);
+ int height = Size2D.Height - (Padding.Top + Padding.Bottom);
+
+ var first = Children.First();
+ var last = Children.Last();
+
+ // slide right out of the viewport
+ await Animation.AnimateTo(last, "PositionX", Size2D.Width);
+
+ // increase width
+ await Animation.AnimateTo(first, "SizeWidth", width);
+ // FIX ME: animating SizeWidth does animate background, but not content => thus, required to reassign size
+ first.Size2D = new Size2D(width, height);
+ }
+ else
+ {
+ int width = (Size2D.Width - (Padding.Start + Padding.End + SplittingSpacing)) / 2;
+
+ var first = Children.Skip(Children.Count - 3).First();
+ var prev = Children.Skip(Children.Count - 2).First();
+ var last = Children.Last();
+
+ // slide right out of the viewport
+ await Animation.AnimateTo(last, "PositionX", Size2D.Width);
+ last.Hide();
+
+ // slide from left to right
+ await Animation.AnimateTo(prev, "PositionX", Padding.Start + width + SplittingSpacing);
+
+ // slide right onto the viewport
+ first.Show();
+ await Animation.AnimateTo(first, "PositionX", (int)Padding.Start);
+ }
+ }
+
+ private async void AddStacking(View child)
+ {
+ Push(child);
+ //int width = Size2D.Width - (Padding.Start + Padding.End);
+ //int height = Size2D.Height - (Padding.Top + Padding.Bottom);
+
+ //if (ChildCount > 1)
+ //{
+ // var prev = Children.Skip(Children.Count - 2).First();
+
+ // // fade out current item
+ // await Animation.AnimateTo(prev, "Opacity", 0.0f);
+ // prev.Hide();
+ //}
+
+ //// show next item behind the screen
+ //child.Size2D = new Size2D(width, height);
+ //child.Position2D = new Position2D(Size2D.Width, Padding.Top);
+ //child.Show();
+
+ //// animate next item to correct position
+ //await Animation.AnimateTo(child, "PositionX", (int)Padding.Start);
+ }
+
+ private async Task RemoveStacking(View child)
+ {
+ Pop();
+ //var last = Children.Last();
+ //await Animation.AnimateTo(last, "PositionX", Size2D.Width);
+ //last.Hide();
+
+ //var prev = Children.Skip(Children.Count - 2).First();
+ //if (prev != null)
+ //{
+ // prev.Show();
+ // await Animation.AnimateTo(prev, "Opacity", 1.0f);
+ //}
+ }
+
+ private List<View> views = new List<View>();
+ private List<View> viewsToRemove = new List<View>();
+
+ private Tizen.NUI.Animation pageEnterAnimation;
+ private Tizen.NUI.Animation pageLeaveAnimation;
+ private Tizen.NUI.Animation opacityEffectAnimation;
+
+ /// <summary>
+ /// Informs about transition animation end
+ /// </summary>Add
+ public event EventHandler TransitionFinished;
+
+ /// <summary>
+ /// Number of pixels between stack right boundary and newly pushed child view left boundary,
+ /// which will be applied before starting page entering animation.
+ /// </summary>
+ /// <value></value>
+ public int PagesRightPadding { get; set; } = 0;
+
+ /// <summary>
+ /// Number of pixels between stack right boundary and current top child view left boundary,
+ /// which will be applied after finishing page leaving animation
+ /// </summary>
+ public int PagesLeftPadding { get; set; } = 0;
+
+ /// <summary>
+ /// Duration of page entering and page leaving animations
+ /// </summary>
+ public int ScrollDuration { get; set; } = 125;
+
+ /// <summary>
+ /// Get view currently stacked on Top of ViewStack
+ /// </summary>
+ public View Current
+ {
+ get
+ {
+ return views.Count > 0 ? views[views.Count - 1] : null;
+ }
+ }
+
+ /// <summary>
+ /// Get view currently stacked under Current
+ /// </summary>
+ public View Previous
+ {
+ get
+ {
+ return views.Count > 1 ? views[views.Count - 2] : null;
+ }
+ }
+
+ /// <summary>
+ /// Pop Current view with animation
+ /// </summary>
+ public void Pop()
+ {
+ if (Current != null)
+ {
+ FinishAnimations();
+ RemoveAllDelayedViews();
+ StartPageLeaveAnimation(Previous, Current);
+ StartShowAnimation(Previous);
+ AddViewToDelayRemove(Current);
+ views.Remove(Current);
+ }
+ }
+
+ /// <summary>
+ /// Pushed new view on stack with animation.
+ /// </summary>
+ public void Push(View view)
+ {
+ FinishAnimations();
+ RemoveAllDelayedViews();
+ Add(view);
+ views.Add(view);
+ StartPageEnterAnimation(Previous, Current);
+ StartHideAnimation(Previous);
+ }
+
+ protected override void Dispose(Tizen.NUI.DisposeTypes type)
+ {
+ if (disposed)
+ {
+ return;
+ }
+
+ if (type == DisposeTypes.Explicit)
+ {
+ pageEnterAnimation.Dispose();
+ pageLeaveAnimation.Dispose();
+ }
+
+ base.Dispose(type);
+ }
+
+ private static void FinishAnimation(Tizen.NUI.Animation anim)
+ {
+ if (anim != null)
+ {
+ if (anim.State == Tizen.NUI.Animation.States.Playing)
+ {
+ anim.Stop(Tizen.NUI.Animation.EndActions.StopFinal);
+ }
+
+ anim.Clear();
+ }
+ }
+
+ private void AddViewToDelayRemove(View view)
+ {
+ if (view)
+ {
+ viewsToRemove.Add(view);
+ }
+ }
+
+ private void RemoveAllDelayedViews()
+ {
+ foreach (View view in viewsToRemove)
+ {
+ // hide view to resolve issue with rendering artifacts
+ view.Hide();
+ Remove(view);
+ view.Dispose();
+ }
+
+ viewsToRemove.Clear();
+ }
+
+ private void FinishAnimations()
+ {
+ FinishAnimation(pageLeaveAnimation);
+ FinishAnimation(pageEnterAnimation);
+ FinishAnimation(opacityEffectAnimation);
+ }
+
+ private void StartPageLeaveAnimation(View back, View front)
+ {
+ pageLeaveAnimation.Duration = ScrollDuration;
+ pageLeaveAnimation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine);
+
+ if (back != null)
+ {
+ // place 'back' out of viewport (should be already there)
+ // run animation to place 'back' in viewport
+ pageLeaveAnimation.AnimateTo(back, "PositionX", 0, null);
+ }
+
+ if (front != null)
+ {
+ // place 'front' in viewport (should be already there)
+ // run animation to place 'front' out of viewport
+ pageLeaveAnimation.AnimateTo(front, "PositionX", Size2D.Width + PagesRightPadding);
+ }
+
+ pageLeaveAnimation.Play();
+ }
+
+ private void StartPageEnterAnimation(View back, View front)
+ {
+ pageEnterAnimation.Duration = ScrollDuration;
+ pageEnterAnimation.DefaultAlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine);
+
+ if (back != null)
+ {
+ // place back in viewport (should be already there)
+ // run anim to place 'back' out of viewport
+ int diff = Position2D.X - PagesLeftPadding;
+ pageEnterAnimation.AnimateTo(back, "PositionX", diff);
+ }
+
+ if (front != null)
+ {
+ // place 'front' out of viewport
+ front.Position2D.X = Size2D.Width + PagesRightPadding;
+
+ // run anim to place 'front' on viewport
+ pageEnterAnimation.AnimateTo(front, "PositionX", 0, null);
+ }
+
+ pageEnterAnimation.Play();
+ }
+
+ private void OnPageEntered(object sender, EventArgs args)
+ {
+ TransitionFinished?.Invoke(this, new EventArgs());
+ }
+
+ private void OnPageLeave(object sender, EventArgs args)
+ {
+ RemoveAllDelayedViews();
+ TransitionFinished?.Invoke(this, new EventArgs());
+ }
+
+ private void StartHideAnimation(View view)
+ {
+ StartOpacityAnimation(view, 1.0f, 0.0f);
+ }
+
+ private void StartShowAnimation(View view)
+ {
+ StartOpacityAnimation(view, 0.0f, 1.0f);
+ }
+
+ private void StartOpacityAnimation(View view, float from, float to)
+ {
+ if (view != null)
+ {
+ opacityEffectAnimation.Duration = ScrollDuration;
+ view.Opacity = from;
+ opacityEffectAnimation.AnimateTo(view, "Opacity", to);
+ opacityEffectAnimation.Play();
+ }
+ }
+
+ //private class ViewStackBaseCustomLayout : LayoutGroup
+ //{
+ // protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
+ // {
+ // OrientationalView stack = this.Owner as OrientationalView;
+
+ // if (!stack)
+ // {
+ // return;
+ // }
+
+ // int totalWidth = stack.Size2D.Width;
+ // int totalHeight = stack.Size2D.Height;
+
+ // SetMeasuredDimensions(
+ // ResolveSizeAndState(new LayoutLength(totalWidth), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK),
+ // ResolveSizeAndState(new LayoutLength(totalHeight), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK));
+ // }
+
+ // protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
+ // {
+ // OrientationalView stack = this.Owner as OrientationalView;
+
+ // if (!changed || !stack)
+ // {
+ // return;
+ // }
+
+ // int totalWidth = stack.Size2D.Width;
+ // int totalHeight = stack.Size2D.Height;
+
+ // foreach (LayoutItem childLayout in LayoutChildren)
+ // {
+ // if (childLayout.Owner == stack.Current)
+ // {
+ // childLayout.Layout(
+ // new LayoutLength(0),
+ // new LayoutLength(0),
+ // new LayoutLength(totalWidth),
+ // new LayoutLength(totalHeight));
+ // }
+ // else
+ // {
+ // childLayout.Layout(
+ // new LayoutLength(-stack.PagesLeftPadding),
+ // new LayoutLength(0),
+ // new LayoutLength(totalWidth - stack.PagesLeftPadding),
+ // new LayoutLength(totalHeight));
+ // }
+ // }
+ // }
+ //}
+ }
+}
namespace Oobe.Views
{
/// <summary>
- /// Implementation of OOBE GUI Guideline for IoT Headed
+ /// Implementation of OOBE GUI Guideline for IoT Headed
/// </summary>
- public class MainView : View
+ public class MainView : ScalableUI.MarginalView
{
private const int TransitionTime = 750;
private readonly Extents stackMargin = new Extents(48, 48, 48, 48);
- private ViewStack stack;
+ //private ViewStack stack;
+ private ScalableUI.OrientationalView orientational;
private Pagination pagination;
public MainView(Window win)
: base()
{
- BackgroundImage = NUIApplication.Current.DirectoryInfo.Resource + "0_BG_dark.png";
-
Size2D stackSize = new Size2D(
win.WindowSize.Width - stackMargin.Start - stackMargin.End,
win.WindowSize.Height - stackMargin.Top - stackMargin.Bottom);
+ BackgroundImage = NUIApplication.Current.DirectoryInfo.Resource + "0_BG_dark.png";
+ MaxMargin = 0.25f;
+
/* For testing other resolutions
stackSize.Width = 1280 - stackMargin.Start - stackMargin.End;
stackSize.Height = 720 - stackMargin.Top - stackMargin.Bottom;
*/
- stack = new ViewStack()
+ //stack = new ViewStack()
+ //{
+ // ScrollDuration = TransitionTime,
+ // Position2D = new Position2D(stackMargin.Start, stackMargin.Top),
+ // Size2D = stackSize,
+ // PagesRightPadding = stackMargin.Start,
+ // PagesLeftPadding = (int)(0.5f * stackSize.Width),
+ // ClippingMode = ClippingModeType.Disabled,
+ //};
+
+ orientational = new ScalableUI.OrientationalView
{
- ScrollDuration = TransitionTime,
- Position2D = new Position2D(stackMargin.Start, stackMargin.Top),
- Size2D = stackSize,
- PagesRightPadding = stackMargin.Start,
- PagesLeftPadding = (int)(0.5f * stackSize.Width),
- ClippingMode = ClippingModeType.Disabled,
+ LandscapeMode = ScalableUI.OrientationalView.Mode.Stacking,
+ PositionUsesPivotPoint = true,
+ ParentOrigin = Position.ParentOriginCenter,
+ PivotPoint = Position.PivotPointCenter,
+ //Position2D = new Position2D(0, 0),
+ Padding = stackMargin,
+ Size2D = this.Size
};
+ Add(orientational);
+
pagination = new Pagination();
pagination.PositionUsesPivotPoint = true;
pagination.PivotPoint = new Position(0.5f, 1.0f);
};
pagination.IndicatorSpacing = 12;
- Add(stack);
+ //Add(stack);
Add(pagination);
}
view.WidthResizePolicy = ResizePolicyType.FillToParent;
pagination.SelectedIndex = pagination.SelectedIndex + 1;
- stack.Push(view);
+ orientational.Add(view);
+ //stack.Push(view);
}
public void Pop()
{
pagination.SelectedIndex = pagination.SelectedIndex - 1;
- stack.Pop();
+ orientational.RemoveLastAdded();
+ //stack.Pop();
}
protected override void Dispose(DisposeTypes type)
if (type == DisposeTypes.Explicit)
{
- stack.Dispose();
+ //stack.Dispose();
pagination.Dispose();
+ orientational.Dispose();
}
base.Dispose(type);